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();
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 
1910 
1911  // COMPATIBILITY FLAGS END
1912 
1913  // Import magic doptypography information, if its there
1914  if (m_xWwFib->m_nFib > 105)
1915  ImportDopTypography(m_xWDop->doptypography);
1916 
1917  // disable form design mode to be able to use imported controls directly
1918  // #i31239# always disable form design mode, not only in protected docs
1919  uno::Reference<beans::XPropertySet> xDocProps(m_pDocShell->GetModel(), uno::UNO_QUERY);
1920  if (xDocProps.is())
1921  {
1922  uno::Reference<beans::XPropertySetInfo> xInfo = xDocProps->getPropertySetInfo();
1923  if (xInfo.is())
1924  {
1925  if (xInfo->hasPropertyByName("ApplyFormDesignMode"))
1926  xDocProps->setPropertyValue("ApplyFormDesignMode", css::uno::makeAny(false));
1927  }
1928  }
1929 
1930  // Still allow editing of form fields.
1931  if (!m_xWDop->fProtEnabled)
1932  m_pDocShell->SetModifyPasswordHash(m_xWDop->lKeyProtDoc);
1933  else if ( xDocProps.is() )
1934  {
1935  comphelper::SequenceAsHashMap aGrabBag(xDocProps->getPropertyValue("InteropGrabBag"));
1936  aGrabBag["FormPasswordHash"] <<= m_xWDop->lKeyProtDoc;
1937  xDocProps->setPropertyValue("InteropGrabBag", uno::Any(aGrabBag.getAsConstPropertyValueList()));
1938  }
1939 
1940  const SvtFilterOptions& rOpt = SvtFilterOptions::Get();
1941  if (rOpt.IsUseEnhancedFields())
1943 }
1944 
1946 {
1947  switch (rTypo.m_iLevelOfKinsoku)
1948  {
1949  case 2: // custom
1950  {
1951  i18n::ForbiddenCharacters aForbidden(rTypo.m_rgxchFPunct,
1952  rTypo.m_rgxchLPunct);
1954  aForbidden);
1955  // Obviously cannot set the standard level 1 for japanese, so
1956  // bail out now while we can.
1957  if (rTypo.GetConvertedLang() == LANGUAGE_JAPANESE)
1958  return;
1959  }
1960  break;
1961  default:
1962  break;
1963  }
1964 
1965  /*
1966  This MS hack means that level 2 of japanese is not in operation, so we put
1967  in what we know are the MS defaults, there is a complementary reverse
1968  hack in the writer. Its our default as well, but we can set it anyway
1969  as a flag for later.
1970  */
1971  if (!rTypo.m_reserved2)
1972  {
1973  i18n::ForbiddenCharacters aForbidden(WW8DopTypography::GetJapanNotBeginLevel1(),
1976  }
1977 
1979  m_rDoc.getIDocumentSettingAccess().setCharacterCompressionType(static_cast<CharCompressType>(rTypo.m_iJustification));
1980 }
1981 
1986  maTmpPos(*pRdr->m_pPaM->GetPoint()),
1987  mxOldStck(std::move(pRdr->m_xCtrlStck)),
1988  mxOldAnchorStck(std::move(pRdr->m_xAnchorStck)),
1989  mxOldRedlines(std::move(pRdr->m_xRedlineStack)),
1990  mxOldPlcxMan(pRdr->m_xPlcxMan),
1991  mpWFlyPara(std::move(pRdr->m_xWFlyPara)),
1992  mpSFlyPara(std::move(pRdr->m_xSFlyPara)),
1993  mpPreviousNumPaM(pRdr->m_pPreviousNumPaM),
1994  mpPrevNumRule(pRdr->m_pPrevNumRule),
1995  mxTableDesc(std::move(pRdr->m_xTableDesc)),
1996  mnInTable(pRdr->m_nInTable),
1997  mnCurrentColl(pRdr->m_nCurrentColl),
1998  mcSymbol(pRdr->m_cSymbol),
1999  mbIgnoreText(pRdr->m_bIgnoreText),
2000  mbSymbol(pRdr->m_bSymbol),
2001  mbHdFtFootnoteEdn(pRdr->m_bHdFtFootnoteEdn),
2002  mbTxbxFlySection(pRdr->m_bTxbxFlySection),
2003  mbAnl(pRdr->m_bAnl),
2004  mbInHyperlink(pRdr->m_bInHyperlink),
2005  mbPgSecBreak(pRdr->m_bPgSecBreak),
2006  mbWasParaEnd(pRdr->m_bWasParaEnd),
2007  mbHasBorder(pRdr->m_bHasBorder),
2008  mbFirstPara(pRdr->m_bFirstPara)
2009 {
2010  pRdr->m_bSymbol = false;
2011  pRdr->m_bHdFtFootnoteEdn = true;
2012  pRdr->m_bTxbxFlySection = pRdr->m_bAnl = pRdr->m_bPgSecBreak = pRdr->m_bWasParaEnd
2013  = pRdr->m_bHasBorder = false;
2014  pRdr->m_bFirstPara = true;
2015  pRdr->m_nInTable = 0;
2016  pRdr->m_pPreviousNumPaM = nullptr;
2017  pRdr->m_pPrevNumRule = nullptr;
2018  pRdr->m_nCurrentColl = 0;
2019 
2020  pRdr->m_xCtrlStck.reset(new SwWW8FltControlStack(&pRdr->m_rDoc, pRdr->m_nFieldFlags,
2021  *pRdr));
2022 
2023  pRdr->m_xRedlineStack.reset(new sw::util::RedlineStack(pRdr->m_rDoc));
2024 
2025  pRdr->m_xAnchorStck.reset(new SwWW8FltAnchorStack(&pRdr->m_rDoc, pRdr->m_nFieldFlags));
2026 
2027  // Save the attribute manager: we need this as the newly created PLCFx Manager
2028  // access the same FKPs as the old one and their Start-End position changes.
2029  if (pRdr->m_xPlcxMan)
2030  pRdr->m_xPlcxMan->SaveAllPLCFx(maPLCFxSave);
2031 
2032  if (nStartCp != -1)
2033  {
2034  pRdr->m_xPlcxMan.reset(new WW8PLCFMan(pRdr->m_xSBase.get(),
2035  mxOldPlcxMan->GetManType(), nStartCp));
2036  }
2037 
2038  maOldApos.push_back(false);
2039  maOldApos.swap(pRdr->m_aApos);
2040  maOldFieldStack.swap(pRdr->m_aFieldStack);
2041 }
2042 
2044 {
2045  pRdr->m_xWFlyPara = std::move(mpWFlyPara);
2046  pRdr->m_xSFlyPara = std::move(mpSFlyPara);
2048  pRdr->m_pPrevNumRule = mpPrevNumRule;
2049  pRdr->m_xTableDesc = std::move(mxTableDesc);
2050  pRdr->m_cSymbol = mcSymbol;
2051  pRdr->m_bSymbol = mbSymbol;
2052  pRdr->m_bIgnoreText = mbIgnoreText;
2055  pRdr->m_nInTable = mnInTable;
2056  pRdr->m_bAnl = mbAnl;
2057  pRdr->m_bInHyperlink = mbInHyperlink;
2058  pRdr->m_bWasParaEnd = mbWasParaEnd;
2059  pRdr->m_bPgSecBreak = mbPgSecBreak;
2060  pRdr->m_nCurrentColl = mnCurrentColl;
2061  pRdr->m_bHasBorder = mbHasBorder;
2062  pRdr->m_bFirstPara = mbFirstPara;
2063 
2064  // Close all attributes as attributes could be created that extend the Fly
2065  pRdr->DeleteCtrlStack();
2066  pRdr->m_xCtrlStck = std::move(mxOldStck);
2067 
2068  pRdr->m_xRedlineStack->closeall(*pRdr->m_pPaM->GetPoint());
2069  pRdr->m_aFrameRedlines.emplace(std::move(pRdr->m_xRedlineStack));
2070  pRdr->m_xRedlineStack = std::move(mxOldRedlines);
2071 
2072  pRdr->DeleteAnchorStack();
2073  pRdr->m_xAnchorStck = std::move(mxOldAnchorStck);
2074 
2075  *pRdr->m_pPaM->GetPoint() = maTmpPos;
2076 
2077  if (mxOldPlcxMan != pRdr->m_xPlcxMan)
2078  pRdr->m_xPlcxMan = mxOldPlcxMan;
2079  if (pRdr->m_xPlcxMan)
2080  pRdr->m_xPlcxMan->RestoreAllPLCFx(maPLCFxSave);
2081  pRdr->m_aApos.swap(maOldApos);
2082  pRdr->m_aFieldStack.swap(maOldFieldStack);
2083 }
2084 
2086  WW8_CP nStartCp, WW8_CP nLen, ManTypes nType )
2087 {
2088  if (nStartCp < 0 || nLen < 0)
2089  return;
2090 
2091  // Saves Flags (amongst other things) and resets them
2092  WW8ReaderSave aSave( this );
2093 
2094  m_pPaM->GetPoint()->nNode = pSttIdx->GetIndex() + 1;
2096 
2097  // Read Text for Header, Footer or Footnote
2098  ReadText( nStartCp, nLen, nType ); // Ignore Sepx when doing so
2099  aSave.Restore( this );
2100 }
2101 
2106 {
2107  WW8PLCFx_SubDoc* pSD = m_xPlcxMan->GetAtn();
2108  if (!pSD)
2109  return 0;
2110 
2111  const void* pData = pSD->GetData();
2112  if (!pData)
2113  return 0;
2114 
2115  OUString sAuthor;
2116  OUString sInitials;
2117  if( m_bVer67 )
2118  {
2119  const WW67_ATRD* pDescri = static_cast<const WW67_ATRD*>(pData);
2120  const OUString* pA = GetAnnotationAuthor(SVBT16ToUInt16(pDescri->ibst));
2121  if (pA)
2122  sAuthor = *pA;
2123  else
2124  {
2125  const sal_uInt8 nLen = std::min<sal_uInt8>(pDescri->xstUsrInitl[0],
2126  SAL_N_ELEMENTS(pDescri->xstUsrInitl)-1);
2127  sAuthor = OUString(pDescri->xstUsrInitl + 1, nLen, RTL_TEXTENCODING_MS_1252);
2128  }
2129  }
2130  else
2131  {
2132  const WW8_ATRD* pDescri = static_cast<const WW8_ATRD*>(pData);
2133  {
2134  const sal_uInt16 nLen = std::min<sal_uInt16>(SVBT16ToUInt16(pDescri->xstUsrInitl[0]),
2135  SAL_N_ELEMENTS(pDescri->xstUsrInitl)-1);
2136  OUStringBuffer aBuf;
2137  aBuf.setLength(nLen);
2138  for(sal_uInt16 nIdx = 1; nIdx <= nLen; ++nIdx)
2139  aBuf[nIdx-1] = SVBT16ToUInt16(pDescri->xstUsrInitl[nIdx]);
2140  sInitials = aBuf.makeStringAndClear();
2141  }
2142 
2143  if (const OUString* pA = GetAnnotationAuthor(SVBT16ToUInt16(pDescri->ibst)))
2144  sAuthor = *pA;
2145  else
2146  sAuthor = sInitials;
2147  }
2148 
2149  sal_uInt32 nDateTime = 0;
2150 
2151  if (sal_uInt8 * pExtended = m_xPlcxMan->GetExtendedAtrds()) // Word < 2002 has no date data for comments
2152  {
2153  sal_uLong nIndex = pSD->GetIdx() & 0xFFFF; // Index is (stupidly) multiplexed for WW8PLCFx_SubDocs
2154  if (m_xWwFib->m_lcbAtrdExtra/18 > nIndex)
2155  nDateTime = SVBT32ToUInt32(*reinterpret_cast<SVBT32*>(pExtended+(nIndex*18)));
2156  }
2157 
2158  DateTime aDate = msfilter::util::DTTM2DateTime(nDateTime);
2159 
2160  OUString sText;
2161  std::unique_ptr<OutlinerParaObject> pOutliner = ImportAsOutliner( sText, pRes->nCp2OrIdx,
2162  pRes->nCp2OrIdx + pRes->nMemLen, MAN_AND );
2163 
2164  m_pFormatOfJustInsertedApo = nullptr;
2165  SwPostItField aPostIt(
2166  static_cast<SwPostItFieldType*>(m_rDoc.getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::Postit)), sAuthor,
2167  sText, sInitials, OUString(), aDate );
2168  aPostIt.SetTextObject(std::move(pOutliner));
2169 
2170  SwPaM aEnd(*m_pPaM->End(), *m_pPaM->End());
2171  m_xCtrlStck->NewAttr(*aEnd.GetPoint(), SvxCharHiddenItem(false, RES_CHRATR_HIDDEN));
2173  m_xCtrlStck->SetAttr(*aEnd.GetPoint(), RES_CHRATR_HIDDEN);
2174  // If this is a range, make sure that it ends after the just inserted character, not before it.
2176 
2177  return 0;
2178 }
2179 
2181  SwFrameFormat const &rHdFtFormat, sal_uInt16 nPageWidth)
2182 {
2183  const SwNodeIndex* pSttIdx = rHdFtFormat.GetContent().GetContentIdx();
2184  OSL_ENSURE(pSttIdx, "impossible");
2185  if (!pSttIdx)
2186  return;
2187 
2188  SwPosition aTmpPos(*m_pPaM->GetPoint());
2189 
2190  m_pPaM->GetPoint()->nNode = pSttIdx->GetIndex() + 1;
2192 
2193  // tdf#122425: Explicitly remove borders and spacing
2196 
2197  SwFlyFrameFormat* pFrame
2198  = m_rDoc.MakeFlySection(RndStdIds::FLY_AT_PARA, m_pPaM->GetPoint(), &aFlySet);
2199 
2200  SwFormatAnchor aAnch( pFrame->GetAnchor() );
2201  aAnch.SetType( RndStdIds::FLY_AT_PARA );
2202  pFrame->SetFormatAttr( aAnch );
2203  SwFormatFrameSize aSz(ATT_MIN_SIZE, nPageWidth, MINLAY);
2204  SwFrameSize eFrameSize = ATT_MIN_SIZE;
2205  if( eFrameSize != aSz.GetWidthSizeType() )
2206  aSz.SetWidthSizeType( eFrameSize );
2207  pFrame->SetFormatAttr(aSz);
2208  pFrame->SetFormatAttr(SwFormatSurround(css::text::WrapTextMode_THROUGH));
2210 
2211  // #i43427# - send frame for header/footer into background.
2212  pFrame->SetFormatAttr( SvxOpaqueItem( RES_OPAQUE, false ) );
2213  SdrObject* pFrameObj = CreateContactObject( pFrame );
2214  OSL_ENSURE( pFrameObj,
2215  "<SwWW8ImplReader::Read_HdFtTextAsHackedFrame(..)> - missing SdrObject instance" );
2216  if ( pFrameObj )
2217  {
2218  pFrameObj->SetOrdNum( 0 );
2219  }
2220  MoveInsideFly(pFrame);
2221 
2222  const SwNodeIndex* pHackIdx = pFrame->GetContent().GetContentIdx();
2223 
2224  Read_HdFtFootnoteText(pHackIdx, nStart, nLen - 1, MAN_HDFT);
2225 
2226  MoveOutsideFly(pFrame, aTmpPos);
2227 }
2228 
2229 void SwWW8ImplReader::Read_HdFtText(WW8_CP nStart, WW8_CP nLen, SwFrameFormat const * pHdFtFormat)
2230 {
2231  const SwNodeIndex* pSttIdx = pHdFtFormat->GetContent().GetContentIdx();
2232  if (!pSttIdx)
2233  return;
2234 
2235  SwPosition aTmpPos( *m_pPaM->GetPoint() ); // Remember old cursor position
2236 
2237  Read_HdFtFootnoteText(pSttIdx, nStart, nLen - 1, MAN_HDFT);
2238 
2239  *m_pPaM->GetPoint() = aTmpPos;
2240 }
2241 
2243 {
2244  // Each CP of Plcfhdd MUST be less than FibRgLw97.ccpHdd
2245  return (nHeaderCP < m_xWwFib->m_ccpHdr && nHeaderCP >= 0);
2246 }
2247 
2249  int nSect)
2250 {
2251  if (m_xHdFt)
2252  {
2253  WW8_CP nStart, nLen;
2254  sal_uInt8 nNumber = 5;
2255 
2256  for( sal_uInt8 nI = 0x20; nI; nI >>= 1, nNumber-- )
2257  {
2258  if (nI & nWhichItems)
2259  {
2260  bool bOk = true;
2261  if( m_bVer67 )
2262  bOk = ( m_xHdFt->GetTextPos(grpfIhdt, nI, nStart, nLen ) && nStart >= 0 && nLen >= 2 );
2263  else
2264  {
2265  m_xHdFt->GetTextPosExact( static_cast< short >(nNumber + (nSect+1)*6), nStart, nLen);
2266  bOk = ( 2 <= nLen ) && isValid_HdFt_CP(nStart);
2267  }
2268 
2269  if (bOk)
2270  return true;
2271  }
2272  }
2273  }
2274  return false;
2275 }
2276 
2277 void SwWW8ImplReader::Read_HdFt(int nSect, const SwPageDesc *pPrev,
2278  const wwSection &rSection)
2279 {
2280  sal_uInt8 grpfIhdt = rSection.maSep.grpfIhdt;
2281  SwPageDesc *pPD = rSection.mpPage;
2282 
2283  if( m_xHdFt )
2284  {
2285  WW8_CP nStart, nLen;
2286  sal_uInt8 nNumber = 5;
2287 
2288  // This loops through the 6 flags WW8_{FOOTER,HEADER}_{ODD,EVEN,FIRST}
2289  // corresponding to bit fields in grpfIhdt indicating which
2290  // header/footer(s) are present in this section
2291  for( sal_uInt8 nI = 0x20; nI; nI >>= 1, nNumber-- )
2292  {
2293  if (nI & grpfIhdt)
2294  {
2295  bool bOk = true;
2296  if( m_bVer67 )
2297  bOk = ( m_xHdFt->GetTextPos(grpfIhdt, nI, nStart, nLen ) && nLen >= 2 );
2298  else
2299  {
2300  m_xHdFt->GetTextPosExact( static_cast< short >(nNumber + (nSect+1)*6), nStart, nLen);
2301  bOk = ( 2 <= nLen ) && isValid_HdFt_CP(nStart);
2302  }
2303 
2304  bool bUseLeft
2305  = (nI & ( WW8_HEADER_EVEN | WW8_FOOTER_EVEN )) != 0;
2306  bool bUseFirst
2307  = (nI & ( WW8_HEADER_FIRST | WW8_FOOTER_FIRST )) != 0;
2308 
2309  // If we are loading a first-page header/footer which is not
2310  // actually enabled in this section (it still needs to be
2311  // loaded as it may be inherited by a later section)
2312  bool bDisabledFirst = bUseFirst && !rSection.HasTitlePage();
2313 
2314  bool bFooter
2315  = (nI & ( WW8_FOOTER_EVEN | WW8_FOOTER_ODD | WW8_FOOTER_FIRST )) != 0;
2316 
2317  SwFrameFormat& rFormat = bUseLeft ? pPD->GetLeft()
2318  : bUseFirst ? pPD->GetFirstMaster()
2319  : pPD->GetMaster();
2320 
2321  SwFrameFormat* pHdFtFormat;
2322  // If we have empty first page header and footer.
2323  bool bNoFirst = !(grpfIhdt & WW8_HEADER_FIRST) && !(grpfIhdt & WW8_FOOTER_FIRST);
2324  if (bFooter)
2325  {
2326  m_bIsFooter = true;
2327  //#i17196# Cannot have left without right
2328  if (!bDisabledFirst
2329  && !pPD->GetMaster().GetFooter().GetFooterFormat())
2330  pPD->GetMaster().SetFormatAttr(SwFormatFooter(true));
2331  if (bUseLeft)
2332  pPD->GetLeft().SetFormatAttr(SwFormatFooter(true));
2333  if (bUseFirst || (rSection.maSep.fTitlePage && bNoFirst))
2335  pHdFtFormat = const_cast<SwFrameFormat*>(rFormat.GetFooter().GetFooterFormat());
2336  }
2337  else
2338  {
2339  m_bIsHeader = true;
2340  //#i17196# Cannot have left without right
2341  if (!bDisabledFirst
2342  && !pPD->GetMaster().GetHeader().GetHeaderFormat())
2343  pPD->GetMaster().SetFormatAttr(SwFormatHeader(true));
2344  if (bUseLeft)
2345  pPD->GetLeft().SetFormatAttr(SwFormatHeader(true));
2346  if (bUseFirst || (rSection.maSep.fTitlePage && bNoFirst))
2348  pHdFtFormat = const_cast<SwFrameFormat*>(rFormat.GetHeader().GetHeaderFormat());
2349  }
2350 
2351  if (bOk)
2352  {
2353  bool bHackRequired = false;
2354  if (m_bIsHeader && rSection.IsFixedHeightHeader())
2355  bHackRequired = true;
2356  else if (m_bIsFooter && rSection.IsFixedHeightFooter())
2357  bHackRequired = true;
2358 
2359  if (bHackRequired)
2360  {
2361  Read_HdFtTextAsHackedFrame(nStart, nLen, *pHdFtFormat,
2362  static_cast< sal_uInt16 >(rSection.GetTextAreaWidth()) );
2363  }
2364  else
2365  Read_HdFtText(nStart, nLen, pHdFtFormat);
2366  }
2367  else if (pPrev)
2368  CopyPageDescHdFt(pPrev, pPD, nI);
2369 
2370  m_bIsHeader = m_bIsFooter = false;
2371  }
2372  }
2373  }
2374 }
2375 
2377 {
2378  return ( mrReader.m_xWDop->fProtEnabled && !rSection.IsNotProtected() );
2379 }
2380 
2381 void wwSectionManager::SetHdFt(wwSection const &rSection, int nSect,
2382  const wwSection *pPrevious)
2383 {
2384  // Header/Footer not present
2385  if (!rSection.maSep.grpfIhdt)
2386  return;
2387 
2388  OSL_ENSURE(rSection.mpPage, "makes no sense to call with a main page");
2389  if (rSection.mpPage)
2390  {
2391  mrReader.Read_HdFt(nSect, pPrevious ? pPrevious->mpPage : nullptr,
2392  rSection);
2393  }
2394 
2395  // Header/Footer - Update Index
2396  // So that the index is still valid later on
2397  if (mrReader.m_xHdFt)
2398  mrReader.m_xHdFt->UpdateIndex(rSection.maSep.grpfIhdt);
2399 
2400 }
2401 
2403 {
2404  SwTextNode* pText = m_pPaM->GetNode().GetTextNode();
2405 
2406  const SwNumRule* pRule = nullptr;
2407 
2408  if (pText != nullptr)
2409  pRule = sw::util::GetNumRuleFromTextNode(*pText);
2410 
2411  if (
2412  pRule && !m_xWDop->fDontUseHTMLAutoSpacing &&
2414  )
2415  {
2416  // If after spacing is set to auto, set the after space to 0
2417  if (m_bParaAutoAfter)
2418  SetLowerSpacing(*m_pPaM, 0);
2419 
2420  // If the previous textnode had numbering and
2421  // and before spacing is set to auto, set before space to 0
2423  SetUpperSpacing(*m_pPaM, 0);
2424 
2425  // If the previous numbering rule was different we need
2426  // to insert a space after the previous paragraph
2427  if((pRule != m_pPrevNumRule) && m_pPreviousNumPaM)
2428  SetLowerSpacing(*m_pPreviousNumPaM, GetParagraphAutoSpace(m_xWDop->fDontUseHTMLAutoSpacing));
2429 
2430  // cache current paragraph
2431  if(m_pPreviousNumPaM)
2432  {
2433  delete m_pPreviousNumPaM;
2434  m_pPreviousNumPaM = nullptr;
2435  }
2436 
2438  m_pPrevNumRule = pRule;
2439  }
2440  else if(!pRule && m_pPreviousNumPaM)
2441  {
2442  // If the previous paragraph has numbering but the current one does not
2443  // we need to add a space after the previous paragraph
2444  SetLowerSpacing(*m_pPreviousNumPaM, GetParagraphAutoSpace(m_xWDop->fDontUseHTMLAutoSpacing));
2445  delete m_pPreviousNumPaM;
2446  m_pPreviousNumPaM = nullptr;
2447  m_pPrevNumRule = nullptr;
2448  }
2449  else
2450  {
2451  // clear paragraph cache
2452  if(m_pPreviousNumPaM)
2453  {
2454  delete m_pPreviousNumPaM;
2455  m_pPreviousNumPaM = nullptr;
2456  }
2457  m_pPrevNumRule = pRule;
2458  }
2459 
2460  // If this is the first paragraph in the document and
2461  // Auto-spacing before paragraph is set,
2462  // set the upper spacing value to 0
2463  if(m_bParaAutoBefore && m_bFirstPara && !m_xWDop->fDontUseHTMLAutoSpacing)
2464  SetUpperSpacing(*m_pPaM, 0);
2465 
2466  m_bFirstPara = false;
2467 
2469 
2470  // We can flush all anchored graphics at the end of a paragraph.
2471  m_xAnchorStck->Flush();
2472 }
2473 
2474 bool SwWW8ImplReader::SetSpacing(SwPaM &rMyPam, int nSpace, bool bIsUpper )
2475 {
2476  bool bRet = false;
2477  const SwPosition* pSpacingPos = rMyPam.GetPoint();
2478 
2479  const SvxULSpaceItem* pULSpaceItem = m_xCtrlStck->GetFormatAttr(*pSpacingPos, RES_UL_SPACE);
2480 
2481  if(pULSpaceItem != nullptr)
2482  {
2483  SvxULSpaceItem aUL(*pULSpaceItem);
2484 
2485  if(bIsUpper)
2486  aUL.SetUpper( static_cast< sal_uInt16 >(nSpace) );
2487  else
2488  aUL.SetLower( static_cast< sal_uInt16 >(nSpace) );
2489 
2490  const sal_Int32 nEnd = pSpacingPos->nContent.GetIndex();
2491  rMyPam.GetPoint()->nContent.Assign(rMyPam.GetContentNode(), 0);
2492  m_xCtrlStck->NewAttr(*pSpacingPos, aUL);
2493  rMyPam.GetPoint()->nContent.Assign(rMyPam.GetContentNode(), nEnd);
2494  m_xCtrlStck->SetAttr(*pSpacingPos, RES_UL_SPACE);
2495  bRet = true;
2496  }
2497  return bRet;
2498 }
2499 
2500 bool SwWW8ImplReader::SetLowerSpacing(SwPaM &rMyPam, int nSpace)
2501 {
2502  return SetSpacing(rMyPam, nSpace, false);
2503 }
2504 
2505 bool SwWW8ImplReader::SetUpperSpacing(SwPaM &rMyPam, int nSpace)
2506 {
2507  return SetSpacing(rMyPam, nSpace, true);
2508 }
2509 
2510 sal_uInt16 SwWW8ImplReader::TabRowSprm(int nLevel) const
2511 {
2512  if (m_bVer67)
2513  return 25;
2514  return nLevel ? 0x244C : 0x2417;
2515 }
2516 
2518 {
2519  // Frame/Table/Anl
2520  if (m_bAnl)
2521  StopAllAnl(); // -> bAnl = false
2522 
2523  while(m_aApos.size() > 1)
2524  {
2525  StopTable();
2526  m_aApos.pop_back();
2527  --m_nInTable;
2528  if (m_aApos[m_nInTable])
2529  StopApo();
2530  }
2531 
2532  if (m_aApos[0])
2533  StopApo();
2534 
2535  OSL_ENSURE(!m_nInTable, "unclosed table!");
2536 }
2537 
2539 {
2540  // This is ww8 version of the code deciding if the table needs to be
2541  // in a floating frame.
2542  // For OOXML code, see SectionPropertyMap::FloatingTableConversion in
2543  // writerfilter/source/dmapper/PropertyMap.cxx
2544  // The two should do ~same, so if you make changes here, please check
2545  // that the other is in sync.
2546 
2547  // Note that this is just a list of heuristics till sw core can have a
2548  // table that is floating and can span over multiple pages at the same
2549  // time.
2550 
2551  bool bResult = true;
2552 
2554  if (nullptr != aRes.pSprm)
2555  {
2556  bResult = false;
2557  WW8TabBandDesc aDesc;
2558  aDesc.ReadDef(false, aRes.pSprm, aRes.nRemainingData);
2559  int nTextAreaWidth = m_aSectionManager.GetTextAreaWidth();
2560  int nTableWidth = aDesc.nCenter[aDesc.nWwCols] - aDesc.nCenter[0];
2561 
2562  // It seems Word has a limit here, so that in case the table width is quite
2563  // close to the text area width, then it won't perform a wrapping, even in
2564  // case the content (e.g. an empty paragraph) would fit. The magic constant
2565  // here represents this limit.
2566  const int nMagicNumber = 469;
2567 
2568  // If the table is wider than the text area, then don't create a fly
2569  // for the table: no wrapping will be performed anyway, but multi-page
2570  // tables will be broken.
2571  if ((nTableWidth + nMagicNumber) < nTextAreaWidth)
2572  bResult = true;
2573 
2574  // If there are columns, do create a fly, as the flow of the columns
2575  // would otherwise restrict the table.
2576  if (!bResult && (m_aSectionManager.CurrentSectionColCount() >= 2))
2577  bResult = true;
2578  }
2579 
2580  if (bResult)
2581  {
2582  WW8PLCFxSave1 aSave;
2583  pPap->Save(aSave);
2584  if (SearchTableEnd(pPap))
2585  {
2586  // Table is considered to be imported into a fly frame and we
2587  // know where the end of the table is.
2588  bool bIsUnicode;
2589  WW8_FC nFc = m_xSBase->WW8Cp2Fc(pPap->Where(), &bIsUnicode);
2590  sal_uInt64 nPos = m_pStrm->Tell();
2591  m_pStrm->Seek(nFc);
2592  sal_uInt16 nUChar = 0;
2593  if (bIsUnicode)
2594  m_pStrm->ReadUInt16(nUChar);
2595  else
2596  {
2597  sal_uInt8 nChar = 0;
2598  m_pStrm->ReadUChar(nChar);
2599  nUChar = nChar;
2600  }
2601  m_pStrm->Seek(nPos);
2602  if (nUChar == 0xc)
2603  // The pap after the table starts with a page break, so
2604  // there will be no wrapping around the float-table.
2605  // Request no fly in this case, so the table can properly
2606  // be a multi-page one if necessary.
2607  bResult = false;
2608  }
2609  pPap->Restore(aSave);
2610  }
2611 
2612  return bResult;
2613 }
2614 
2615 bool SwWW8ImplReader::ProcessSpecial(bool &rbReSync, WW8_CP nStartCp)
2616 {
2617  // Frame/Table/Anl
2618  if (m_bInHyperlink)
2619  return false;
2620 
2621  rbReSync = false;
2622 
2623  OSL_ENSURE(m_nInTable >= 0,"nInTable < 0!");
2624 
2625  // TabRowEnd
2626  bool bTableRowEnd = (m_xPlcxMan->HasParaSprm(m_bVer67 ? 25 : 0x2417).pSprm != nullptr);
2627 
2628 // Unfortunately, for every paragraph we need to check first whether
2629 // they contain a sprm 29 (0x261B), which starts an APO.
2630 // All other sprms then refer to that APO and not to the normal text
2631 // surrounding it.
2632 // The same holds true for a Table (sprm 24 (0x2416)) and Anls (sprm 13).
2633 
2634 // WW: Table in APO is possible (Both Start-Ends occur at the same time)
2635 // WW: APO in Table not possible
2636 
2637 // This mean that of a Table is the content of an APO, the APO start needs
2638 // to be edited first, so that the Table remains in the APO and not the
2639 // other way around.
2640 // At the End, however, we need to edit the Table End first as the APO
2641 // must end after that Table (or else we never find the APO End).
2642 
2643 // The same holds true for Fly / Anl, Tab / Anl, Fly / Tab / Anl.
2644 
2645 // If the Table is within an APO the TabRowEnd Area misses the
2646 // APO settings.
2647 // To not end the APO there, we do not call ProcessApo
2648 
2649 // KHZ: When there is a table inside the Apo the Apo-flags are also
2650 // missing for the 2nd, 3rd... paragraphs of each cell.
2651 
2652 // 1st look for in-table flag, for 2000+ there is a subtable flag to
2653 // be considered, the sprm 6649 gives the level of the table
2654  sal_uInt8 nCellLevel = 0;
2655 
2656  if (m_bVer67)
2657  nCellLevel = int(nullptr != m_xPlcxMan->HasParaSprm(24).pSprm);
2658  else
2659  {
2660  nCellLevel = int(nullptr != m_xPlcxMan->HasParaSprm(0x2416).pSprm);
2661  if (!nCellLevel)
2662  nCellLevel = int(nullptr != m_xPlcxMan->HasParaSprm(0x244B).pSprm);
2663  }
2664  do
2665  {
2666  WW8_TablePos *pTabPos=nullptr;
2667  WW8_TablePos aTabPos;
2668  if(nCellLevel && !m_bVer67)
2669  {
2670  WW8PLCFxSave1 aSave;
2671  m_xPlcxMan->GetPap()->Save( aSave );
2672  rbReSync = true;
2673  WW8PLCFx_Cp_FKP* pPap = m_xPlcxMan->GetPapPLCF();
2674  WW8_CP nMyStartCp=nStartCp;
2675 
2676  SprmResult aLevel = m_xPlcxMan->HasParaSprm(0x6649);
2677  if (aLevel.pSprm && aLevel.nRemainingData >= 1)
2678  nCellLevel = *aLevel.pSprm;
2679 
2680  bool bHasRowEnd = SearchRowEnd(pPap, nMyStartCp, (m_nInTable<nCellLevel?m_nInTable:nCellLevel-1));
2681 
2682  // Bad Table, remain unchanged in level, e.g. #i19667#
2683  if (!bHasRowEnd)
2684  nCellLevel = static_cast< sal_uInt8 >(m_nInTable);
2685 
2686  if (bHasRowEnd && ParseTabPos(&aTabPos,pPap))
2687  pTabPos = &aTabPos;
2688 
2689  m_xPlcxMan->GetPap()->Restore( aSave );
2690  }
2691 
2692  // Then look if we are in an Apo
2693 
2694  ApoTestResults aApo = TestApo(nCellLevel, bTableRowEnd, pTabPos);
2695 
2696  // Look to see if we are in a Table, but Table in foot/end note not allowed
2697  bool bStartTab = (m_nInTable < nCellLevel) && !m_bFootnoteEdn;
2698 
2699  bool bStopTab = m_bWasTabRowEnd && (m_nInTable > nCellLevel) && !m_bFootnoteEdn;
2700 
2701  m_bWasTabRowEnd = false; // must be deactivated right here to prevent next
2702  // WW8TabDesc::TableCellEnd() from making nonsense
2703 
2704  if (m_nInTable && !bTableRowEnd && !bStopTab && (m_nInTable == nCellLevel && aApo.HasStartStop()))
2705  bStopTab = bStartTab = true; // Required to stop and start table
2706 
2707  // Test for Anl (Numbering) and process all events in the right order
2708  if( m_bAnl && !bTableRowEnd )
2709  {
2710  SprmResult aSprm13 = m_xPlcxMan->HasParaSprm(13);
2711  const sal_uInt8* pSprm13 = aSprm13.pSprm;
2712  if (pSprm13 && aSprm13.nRemainingData >= 1)
2713  { // Still Anl left?
2714  sal_uInt8 nT = static_cast< sal_uInt8 >(GetNumType( *pSprm13 ));
2715  if( ( nT != WW8_Pause && nT != m_nWwNumType ) // Anl change
2716  || aApo.HasStartStop() // Forced Anl end
2717  || bStopTab || bStartTab )
2718  {
2719  StopAnlToRestart(nT); // Anl-Restart (= change) over sprms
2720  }
2721  else
2722  {
2723  NextAnlLine( pSprm13 ); // Next Anl Line
2724  }
2725  }
2726  else
2727  { // Regular Anl end
2728  StopAllAnl(); // Actual end
2729  }
2730  }
2731  if (bStopTab)
2732  {
2733  StopTable();
2734  m_aApos.pop_back();
2735  --m_nInTable;
2736  }
2737  if (aApo.mbStopApo)
2738  {
2739  StopApo();
2740  m_aApos[m_nInTable] = false;
2741  }
2742 
2743  if (aApo.mbStartApo)
2744  {
2745  m_aApos[m_nInTable] = StartApo(aApo, pTabPos);
2746  // We need an ReSync after StartApo
2747  // (actually only if the Apo extends past a FKP border)
2748  rbReSync = true;
2749  }
2750  if (bStartTab)
2751  {
2752  WW8PLCFxSave1 aSave;
2753  m_xPlcxMan->GetPap()->Save( aSave );
2754 
2755  // Numbering for cell borders causes a crash -> no Anls in Tables
2756  if (m_bAnl)
2757  StopAllAnl();
2758 
2759  if(m_nInTable < nCellLevel)
2760  {
2761  if (StartTable(nStartCp))
2762  ++m_nInTable;
2763  else
2764  break;
2765  m_aApos.push_back(false);
2766  }
2767 
2768  if(m_nInTable >= nCellLevel)
2769  {
2770  // We need an ReSync after StartTable
2771  // (actually only if the Apo extends past a FKP border)
2772  rbReSync = true;
2773  m_xPlcxMan->GetPap()->Restore( aSave );
2774  }
2775  }
2776  } while (!m_bFootnoteEdn && (m_nInTable < nCellLevel));
2777  return bTableRowEnd;
2778 }
2779 
2781 {
2782  /*
2783  #i22206#/#i52786#
2784  The (default) character set used for a run of text is the default
2785  character set for the version of Word that last saved the document.
2786 
2787  This is a bit tentative, more might be required if the concept is correct.
2788  When later version of word write older 6/95 documents the charset is
2789  correctly set in the character runs involved, so it's hard to reproduce
2790  documents that require this to be sure of the process involved.
2791  */
2792  const SvxLanguageItem *pLang = static_cast<const SvxLanguageItem*>(GetFormatAttr(RES_CHRATR_LANGUAGE));
2793  LanguageType eLang = pLang ? pLang->GetLanguage() : LANGUAGE_SYSTEM;
2794  css::lang::Locale aLocale(LanguageTag::convertToLocale(eLang));
2796 }
2797 
2799 {
2800  /*
2801  #i22206#/#i52786#
2802  The (default) character set used for a run of text is the default
2803  character set for the version of Word that last saved the document.
2804 
2805  This is a bit tentative, more might be required if the concept is correct.
2806  When later version of word write older 6/95 documents the charset is
2807  correctly set in the character runs involved, so it's hard to reproduce
2808  documents that require this to be sure of the process involved.
2809  */
2810  const SvxLanguageItem *pLang = static_cast<const SvxLanguageItem*>(GetFormatAttr(RES_CHRATR_CJK_LANGUAGE));
2811  LanguageType eLang = pLang ? pLang->GetLanguage() : LANGUAGE_SYSTEM;
2812  css::lang::Locale aLocale(LanguageTag::convertToLocale(eLang));
2814 }
2815 
2817 {
2818  /*
2819  #i2015
2820  If the hard charset is set use it, if not see if there is an open
2821  character run that has set the charset, if not then fallback to the
2822  current underlying paragraph style.
2823  */
2824  rtl_TextEncoding eSrcCharSet = m_eHardCharSet;
2825  if (eSrcCharSet == RTL_TEXTENCODING_DONTKNOW)
2826  {
2827  if (!m_bVer67)
2828  eSrcCharSet = GetCharSetFromLanguage();
2829  else if (!m_aFontSrcCharSets.empty())
2830  eSrcCharSet = m_aFontSrcCharSets.top();
2831  if ((eSrcCharSet == RTL_TEXTENCODING_DONTKNOW) && m_nCharFormat >= 0 && static_cast<size_t>(m_nCharFormat) < m_vColl.size() )
2832  eSrcCharSet = m_vColl[m_nCharFormat].GetCharSet();
2833  if ((eSrcCharSet == RTL_TEXTENCODING_DONTKNOW) && StyleExists(m_nCurrentColl) && m_nCurrentColl < m_vColl.size())
2834  eSrcCharSet = m_vColl[m_nCurrentColl].GetCharSet();
2835  if (eSrcCharSet == RTL_TEXTENCODING_DONTKNOW)
2836  eSrcCharSet = GetCharSetFromLanguage();
2837  }
2838  return eSrcCharSet;
2839 }
2840 
2841 //Takashi Ono for CJK
2843 {
2844  /*
2845  #i2015
2846  If the hard charset is set use it, if not see if there is an open
2847  character run that has set the charset, if not then fallback to the
2848  current underlying paragraph style.
2849  */
2850  rtl_TextEncoding eSrcCharSet = m_eHardCharSet;
2851  if (eSrcCharSet == RTL_TEXTENCODING_DONTKNOW)
2852  {
2853  if (!m_aFontSrcCJKCharSets.empty())
2854  eSrcCharSet = m_aFontSrcCJKCharSets.top();
2855  if ((eSrcCharSet == RTL_TEXTENCODING_DONTKNOW) && m_nCharFormat >= 0 && static_cast<size_t>(m_nCharFormat) < m_vColl.size() )
2856  eSrcCharSet = m_vColl[m_nCharFormat].GetCJKCharSet();
2857  if (eSrcCharSet == RTL_TEXTENCODING_DONTKNOW && StyleExists(m_nCurrentColl) && m_nCurrentColl < m_vColl.size())
2858  eSrcCharSet = m_vColl[m_nCurrentColl].GetCJKCharSet();
2859  if (eSrcCharSet == RTL_TEXTENCODING_DONTKNOW)
2860  eSrcCharSet = GetCJKCharSetFromLanguage();
2861  }
2862  return eSrcCharSet;
2863 }
2864 
2866 {
2867  if (m_pPostProcessAttrsInfo != nullptr)
2868  {
2869  SfxItemIter aIter(m_pPostProcessAttrsInfo->mItemSet);
2870 
2871  const SfxPoolItem * pItem = aIter.GetCurItem();
2872  if (pItem != nullptr)
2873  {
2874  do
2875  {
2876  m_xCtrlStck->NewAttr(*m_pPostProcessAttrsInfo->mPaM.GetPoint(),
2877  *pItem);
2878  m_xCtrlStck->SetAttr(*m_pPostProcessAttrsInfo->mPaM.GetMark(),
2879  pItem->Which());
2880  }
2881  while (!aIter.IsAtEnd() && nullptr != (pItem = aIter.NextItem()));
2882  }
2883 
2884  m_pPostProcessAttrsInfo.reset();
2885  }
2886 }
2887 
2888 /*
2889  #i9240#
2890  It appears that some documents that are in a baltic 8 bit encoding which has
2891  some undefined characters can have use made of those characters, in which
2892  case they default to CP1252. If not then it's perhaps that the font encoding
2893  is only in use for 6/7 and for 8+ if we are in 8bit mode then the encoding
2894  is always 1252.
2895 
2896  So an encoding converter that on an undefined character attempts to
2897  convert from 1252 on the undefined character
2898 */
2899 static std::size_t Custom8BitToUnicode(rtl_TextToUnicodeConverter hConverter,
2900  sal_Char const *pIn, std::size_t nInLen, sal_Unicode *pOut, std::size_t nOutLen)
2901 {
2902  const sal_uInt32 nFlags =
2903  RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR |
2904  RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR |
2905  RTL_TEXTTOUNICODE_FLAGS_INVALID_IGNORE |
2906  RTL_TEXTTOUNICODE_FLAGS_FLUSH;
2907 
2908  const sal_uInt32 nFlags2 =
2909  RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_IGNORE |
2910  RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_IGNORE |
2911  RTL_TEXTTOUNICODE_FLAGS_INVALID_IGNORE |
2912  RTL_TEXTTOUNICODE_FLAGS_FLUSH;
2913 
2914  std::size_t nDestChars=0;
2915  std::size_t nConverted=0;
2916 
2917  do
2918  {
2919  sal_uInt32 nInfo = 0;
2920  sal_Size nThisConverted=0;
2921 
2922  nDestChars += rtl_convertTextToUnicode(hConverter, nullptr,
2923  pIn+nConverted, nInLen-nConverted,
2924  pOut+nDestChars, nOutLen-nDestChars,
2925  nFlags, &nInfo, &nThisConverted);
2926 
2927  OSL_ENSURE(nInfo == 0, "A character conversion failed!");
2928 
2929  nConverted += nThisConverted;
2930 
2931  if (
2932  nInfo & RTL_TEXTTOUNICODE_INFO_UNDEFINED ||
2933  nInfo & RTL_TEXTTOUNICODE_INFO_MBUNDEFINED
2934  )
2935  {
2936  sal_Size nOtherConverted;
2937  rtl_TextToUnicodeConverter hCP1252Converter =
2938  rtl_createTextToUnicodeConverter(RTL_TEXTENCODING_MS_1252);
2939  nDestChars += rtl_convertTextToUnicode(hCP1252Converter, nullptr,
2940  pIn+nConverted, 1,
2941  pOut+nDestChars, nOutLen-nDestChars,
2942  nFlags2, &nInfo, &nOtherConverted);
2943  rtl_destroyTextToUnicodeConverter(hCP1252Converter);
2944  nConverted+=1;
2945  }
2946  } while (nConverted < nInLen);
2947 
2948  return nDestChars;
2949 }
2950 
2952 {
2953  bool bResult = false;
2954 
2955  switch (static_cast<sal_uInt16>(nLang))
2956  {
2957  case 0x1401: // Arabic(Algeria)
2958  case 0x3c01: // Arabic(Bahrain)
2959  case 0xc01: // Arabic(Egypt)
2960  case 0x801: // Arabic(Iraq)
2961  case 0x2c01: // Arabic (Jordan)
2962  case 0x3401: // Arabic(Kuwait)
2963  case 0x3001: // Arabic(Lebanon)
2964  case 0x1001: // Arabic(Libya)
2965  case 0x1801: // Arabic(Morocco)
2966  case 0x2001: // Arabic(Oman)
2967  case 0x4001: // Arabic(Qatar)
2968  case 0x401: // Arabic(Saudi Arabia)
2969  case 0x2801: // Arabic(Syria)
2970  case 0x1c01: // Arabic(Tunisia)
2971  case 0x3801: // Arabic(U.A.E)
2972  case 0x2401: // Arabic(Yemen)
2973  bResult = true;
2974  break;
2975  default:
2976  break;
2977  }
2978 
2979  return bResult;
2980 }
2981 
2983 {
2984  if (nChar >= 0x0030 && nChar <= 0x0039)
2985  return nChar + 0x0630;
2986 
2987  return nChar;
2988 }
2989 
2990 namespace
2991 {
2992  OUString makeOUString(rtl_uString *pStr, sal_Int32 nAllocLen)
2993  {
2994  //if read len was in or around that of allocated len, just reuse pStr
2995  if (nAllocLen < pStr->length + 256)
2996  return OUString(pStr, SAL_NO_ACQUIRE);
2997  //otherwise copy the shorter used section to release extra mem
2998  OUString sRet(pStr->buffer, pStr->length);
2999  rtl_uString_release(pStr);
3000  return sRet;
3001  }
3002 }
3003 
3007 bool SwWW8ImplReader::ReadPlainChars(WW8_CP& rPos, sal_Int32 nEnd, sal_Int32 nCpOfs)
3008 {
3009  sal_Int32 nRequestedStrLen = nEnd - rPos;
3010 
3011  OSL_ENSURE(nRequestedStrLen, "String is 0");
3012  if (nRequestedStrLen <= 0)
3013  return true;
3014 
3015  sal_Int32 nRequestedPos = m_xSBase->WW8Cp2Fc(nCpOfs+rPos, &m_bIsUnicode);
3016  bool bValidPos = checkSeek(*m_pStrm, nRequestedPos);
3017  OSL_ENSURE(bValidPos, "Document claimed to have more text than available");
3018  if (!bValidPos)
3019  {
3020  // Swallow missing range, e.g. #i95550#
3021  rPos+=nRequestedStrLen;
3022  return true;
3023  }
3024 
3025  std::size_t nAvailableStrLen = m_pStrm->remainingSize() / (m_bIsUnicode ? 2 : 1);
3026  OSL_ENSURE(nAvailableStrLen, "Document claimed to have more text than available");
3027  if (!nAvailableStrLen)
3028  {
3029  // Swallow missing range, e.g. #i95550#
3030  rPos+=nRequestedStrLen;
3031  return true;
3032  }
3033 
3034  sal_Int32 nValidStrLen = std::min<std::size_t>(nRequestedStrLen, nAvailableStrLen);
3035 
3036  // Reset Unicode flag and correct FilePos if needed.
3037  // Note: Seek is not expensive, as we're checking inline whether or not
3038  // the correct FilePos has already been reached.
3039  const sal_Int32 nStrLen = std::min(nValidStrLen, SAL_MAX_INT32-1);
3040 
3041  rtl_TextEncoding eSrcCharSet = m_bVer67 ? GetCurrentCharSet() :
3042  RTL_TEXTENCODING_MS_1252;
3043  if (m_bVer67 && eSrcCharSet == RTL_TEXTENCODING_MS_932)
3044  {
3045  /*
3046  fdo#82904
3047 
3048  Older documents exported as word 95 that use unicode aware fonts will
3049  have the charset of those fonts set to RTL_TEXTENCODING_MS_932 on
3050  export as the conversion from RTL_TEXTENCODING_UNICODE. This is a serious
3051  pain.
3052 
3053  We will try and use a fallback encoding if the conversion from
3054  RTL_TEXTENCODING_MS_932 fails, but you can get unlucky and get a document
3055  which isn't really in RTL_TEXTENCODING_MS_932 but parts of it form
3056  valid RTL_TEXTENCODING_MS_932 by chance :-(
3057 
3058  We're not the only ones that struggle with this: Here's the help from
3059  MSOffice 2003 on the topic:
3060 
3061  <<
3062  Earlier versions of Microsoft Word were sometimes used in conjunction with
3063  third-party language-processing add-in programs designed to support Chinese or
3064  Korean on English versions of Microsoft Windows. Use of these add-ins sometimes
3065  results in incorrect text display in more recent versions of Word.
3066 
3067  However, you can set options to convert these documents so that text is
3068  displayed correctly. On the Tools menu, click Options, and then click the
3069  General tab. In the English Word 6.0/95 documents list, select Contain Asian
3070  text (to have Word interpret the text as Asian code page data, regardless of
3071  its font) or Automatically detect Asian text (to have Word attempt to determine
3072  which parts of the text are meant to be Asian).
3073  >>
3074 
3075  What we can try here is to ignore a RTL_TEXTENCODING_MS_932 codepage if
3076  the language is not Japanese
3077  */
3078 
3080  if (pItem != nullptr && LANGUAGE_JAPANESE != static_cast<const SvxLanguageItem *>(pItem)->GetLanguage())
3081  {
3082  SAL_WARN("sw.ww8", "discarding word95 RTL_TEXTENCODING_MS_932 encoding");
3083  eSrcCharSet = GetCharSetFromLanguage();
3084  }
3085  }
3086  const rtl_TextEncoding eSrcCJKCharSet = m_bVer67 ? GetCurrentCJKCharSet() :
3087  RTL_TEXTENCODING_MS_1252;
3088 
3089  // allocate unicode string data
3090  rtl_uString *pStr = rtl_uString_alloc(nStrLen);
3091  sal_Unicode* pBuffer = pStr->buffer;
3092  sal_Unicode* pWork = pBuffer;
3093 
3094  std::unique_ptr<sal_Char[]> p8Bits;
3095 
3096  rtl_TextToUnicodeConverter hConverter = nullptr;
3097  if (!m_bIsUnicode || m_bVer67)
3098  hConverter = rtl_createTextToUnicodeConverter(eSrcCharSet);
3099 
3100  if (!m_bIsUnicode)
3101  p8Bits.reset( new sal_Char[nStrLen] );
3102 
3103  // read the stream data
3104  sal_uInt8 nBCode = 0;
3105  sal_uInt16 nUCode;
3106 
3107  LanguageType nCTLLang = LANGUAGE_SYSTEM;
3109  if (pItem != nullptr)
3110  nCTLLang = static_cast<const SvxLanguageItem *>(pItem)->GetLanguage();
3111 
3112  sal_Int32 nL2;
3113  for (nL2 = 0; nL2 < nStrLen; ++nL2)
3114  {
3115  if (m_bIsUnicode)
3116  m_pStrm->ReadUInt16( nUCode ); // unicode --> read 2 bytes
3117  else
3118  {
3119  m_pStrm->ReadUChar( nBCode ); // old code --> read 1 byte
3120  nUCode = nBCode;
3121  }
3122 
3123  if (m_pStrm->GetError())
3124  {
3125  rPos = WW8_CP_MAX-10; // -> eof or other error
3126  std::free(pStr);
3127  return true;
3128  }
3129 
3130  if ((32 > nUCode) || (0xa0 == nUCode))
3131  {
3132  m_pStrm->SeekRel( m_bIsUnicode ? -2 : -1 );
3133  break; // Special character < 32, == 0xa0 found
3134  }
3135 
3136  if (m_bIsUnicode)
3137  {
3138  if (!m_bVer67)
3139  *pWork++ = nUCode;
3140  else
3141  {
3142  if (nUCode >= 0x3000) //0x8000 ?
3143  {
3144  sal_Char aTest[2];
3145  aTest[0] = static_cast< sal_Char >((nUCode & 0xFF00) >> 8);
3146  aTest[1] = static_cast< sal_Char >(nUCode & 0x00FF);
3147  OUString aTemp(aTest, 2, eSrcCJKCharSet);
3148  OSL_ENSURE(aTemp.getLength() == 1, "so much for that theory");
3149  *pWork++ = aTemp[0];
3150  }
3151  else
3152  {
3153  sal_Char cTest = static_cast< sal_Char >(nUCode & 0x00FF);
3154  pWork += Custom8BitToUnicode(hConverter, &cTest, 1, pWork, 1);
3155  }
3156  }
3157  }
3158  else
3159  p8Bits[nL2] = nBCode;
3160  }
3161 
3162  if (nL2)
3163  {
3164  const sal_Int32 nEndUsed = !m_bIsUnicode
3165  ? Custom8BitToUnicode(hConverter, p8Bits.get(), nL2, pBuffer, nStrLen)
3166  : pWork - pBuffer;
3167 
3169  {
3170  for (sal_Int32 nI = 0; nI < nEndUsed; ++nI, ++pBuffer)
3171  *pBuffer = TranslateToHindiNumbers(*pBuffer);
3172  }
3173 
3174  pStr->buffer[nEndUsed] = 0;
3175  pStr->length = nEndUsed;
3176 
3177  emulateMSWordAddTextToParagraph(makeOUString(pStr, nStrLen));
3178  pStr = nullptr;
3179  rPos += nL2;
3180  if (!m_aApos.back()) // a para end in apo doesn't count
3181  m_bWasParaEnd = false; // No CR
3182  }
3183 
3184  if (hConverter)
3185  rtl_destroyTextToUnicodeConverter(hConverter);
3186  if (pStr)
3187  rtl_uString_release(pStr);
3188  return nL2 >= nStrLen;
3189 }
3190 
3191 #define MSASCII SAL_MAX_INT16
3192 
3193 namespace
3194 {
3195  // We want to force weak chars inside 0x0020 to 0x007F to LATIN
3196  sal_Int16 lcl_getScriptType(
3197  const uno::Reference<i18n::XBreakIterator>& rBI,
3198  const OUString &rString, sal_Int32 nPos)
3199  {
3200  sal_Int16 nScript = rBI->getScriptType(rString, nPos);
3201  if (nScript == i18n::ScriptType::WEAK && rString[nPos] >= 0x0020 && rString[nPos] <= 0x007F)
3202  nScript = MSASCII;
3203  return nScript;
3204  }
3205 
3206  // We want to know about WEAK segments, so endOfScript isn't
3207  // useful, and see lcl_getScriptType anyway
3208  sal_Int32 lcl_endOfScript(
3209  const uno::Reference<i18n::XBreakIterator>& rBI,
3210  const OUString &rString, sal_Int32 nPos, sal_Int16 nScript)
3211  {
3212  while (nPos < rString.getLength())
3213  {
3214  sal_Int16 nNewScript = lcl_getScriptType(rBI, rString, nPos);
3215  if (nScript != nNewScript)
3216  break;
3217  ++nPos;
3218  }
3219  return nPos;
3220  }
3221 
3222  sal_Int32 lcl_getWriterScriptType(
3223  const uno::Reference<i18n::XBreakIterator>& rBI,
3224  const OUString &rString, sal_Int32 nPos)
3225  {
3226  sal_Int16 nScript = i18n::ScriptType::WEAK;
3227 
3228  if (rString.isEmpty())
3229  return nScript;
3230 
3231  while (nPos >= 0)
3232  {
3233  nScript = rBI->getScriptType(rString, nPos);
3234  if (nScript != i18n::ScriptType::WEAK)
3235  break;
3236  --nPos;
3237  }
3238 
3239  return nScript;
3240  }
3241 
3242  bool samePitchIgnoreUnknown(FontPitch eA, FontPitch eB)
3243  {
3244  return (eA == eB || eA == PITCH_DONTKNOW || eB == PITCH_DONTKNOW);
3245  }
3246 
3247  bool sameFontIgnoringIrrelevantFields(const SvxFontItem &rA, const SvxFontItem &rB)
3248  {
3249  // Ignoring CharSet, and ignoring unknown pitch
3250  return rA.GetFamilyName() == rB.GetFamilyName() &&
3251  rA.GetStyleName() == rB.GetStyleName() &&
3252  rA.GetFamily() == rB.GetFamily() &&
3253  samePitchIgnoreUnknown(rA.GetPitch(), rB.GetPitch());
3254  }
3255 }
3256 
3257 // In writer we categorize text into CJK, CTL and "Western" for everything else.
3258 // Microsoft Word basically categorizes text into East Asian, Complex, ASCII,
3259 // NonEastAsian/HighAnsi, with some shared characters and some properties to
3260 // hint as to which way to bias those shared characters.
3261 
3262 // That's four categories, we however have three categories. Given that problem
3263 // here we would ideally find out "what would word do" to see what font/language
3264 // word would assign to characters based on the unicode range they fall into and
3265 // hack the word one onto the range we use. However it's unclear what word's
3266 // categorization is. So we don't do that here yet.
3267 
3268 // Additional to the categorization, when word encounters weak text for ambiguous
3269 // chars it uses idcthint to indicate which way to bias. We don't have an idcthint
3270 // feature in writer.
3271 
3272 // So what we currently do here then is to split our text into non-weak/weak
3273 // sections and uses word's idcthint to determine what font it would use and
3274 // force that on for the segment. Following what we *do* know about word's
3275 // categorization, we know that the range 0x0020 and 0x007F is sprmCRgFtc0 in
3276 // word, something we map to LATIN, so we consider all weak chars in that range
3277 // to auto-bias to LATIN.
3278 
3279 // See https://bugs.libreoffice.org/show_bug.cgi?id=34319 for an example
3281 {
3282  if (rAddString.isEmpty())
3283  return;
3284 
3285  uno::Reference<i18n::XBreakIterator> xBI(g_pBreakIt->GetBreakIter());
3286  assert(xBI.is());
3287 
3288  sal_Int16 nScript = lcl_getScriptType(xBI, rAddString, 0);
3289  sal_Int32 nLen = rAddString.getLength();
3290 
3291  OUString sParagraphText;
3292  const SwContentNode *pCntNd = m_pPaM->GetContentNode();
3293  const SwTextNode* pNd = pCntNd ? pCntNd->GetTextNode() : nullptr;
3294  if (pNd)
3295  sParagraphText = pNd->GetText();
3296  sal_Int32 nParaOffset = sParagraphText.getLength();
3297  sParagraphText = sParagraphText + rAddString;
3298 
3299  sal_Int32 nPos = 0;
3300  while (nPos < nLen)
3301  {
3302  sal_Int32 nEnd = lcl_endOfScript(xBI, rAddString, nPos, nScript);
3303  if (nEnd < 0)
3304  break;
3305 
3306  OUString sChunk(rAddString.copy(nPos, nEnd-nPos));
3307  const sal_uInt16 aIds[] = {RES_CHRATR_FONT, RES_CHRATR_CJK_FONT, RES_CHRATR_CTL_FONT};
3308  const SvxFontItem *pOverriddenItems[] = {nullptr, nullptr, nullptr};
3309  bool aForced[] = {false, false, false};
3310 
3311  int nLclIdctHint = 0xFF;
3312  if (nScript == i18n::ScriptType::WEAK)
3313  {
3314  const SfxInt16Item *pIdctHint = static_cast<const SfxInt16Item*>(GetFormatAttr(RES_CHRATR_IDCTHINT));
3315  nLclIdctHint = pIdctHint->GetValue();
3316  }
3317  else if (nScript == MSASCII) // Force weak chars in ascii range to use LATIN font
3318  nLclIdctHint = 0;
3319 
3320  sal_uInt16 nForceFromFontId = 0;
3321  if (nLclIdctHint != 0xFF)
3322  {
3323  switch (nLclIdctHint)
3324  {
3325  case 0:
3326  nForceFromFontId = RES_CHRATR_FONT;
3327  break;
3328  case 1:
3329  nForceFromFontId = RES_CHRATR_CJK_FONT;
3330  break;
3331  case 2:
3332  nForceFromFontId = RES_CHRATR_CTL_FONT;
3333  break;
3334  default:
3335  break;
3336  }
3337  }
3338 
3339  if (nForceFromFontId != 0)
3340  {
3341  // Now we know that word would use the nForceFromFontId font for this range
3342  // Try and determine what script writer would assign this range to
3343 
3344  sal_Int32 nWriterScript = lcl_getWriterScriptType(xBI, sParagraphText,
3345  nPos + nParaOffset);
3346 
3347  bool bWriterWillUseSameFontAsWordAutomatically = false;
3348 
3349  if (nWriterScript != i18n::ScriptType::WEAK)
3350  {
3351  if (
3352  (nWriterScript == i18n::ScriptType::ASIAN && nForceFromFontId == RES_CHRATR_CJK_FONT) ||
3353  (nWriterScript == i18n::ScriptType::COMPLEX && nForceFromFontId == RES_CHRATR_CTL_FONT) ||
3354  (nWriterScript == i18n::ScriptType::LATIN && nForceFromFontId == RES_CHRATR_FONT)
3355  )
3356  {
3357  bWriterWillUseSameFontAsWordAutomatically = true;
3358  }
3359  else
3360  {
3361  const SvxFontItem *pSourceFont = static_cast<const SvxFontItem*>(GetFormatAttr(nForceFromFontId));
3362  sal_uInt16 nDestId = aIds[nWriterScript-1];
3363  const SvxFontItem *pDestFont = static_cast<const SvxFontItem*>(GetFormatAttr(nDestId));
3364  bWriterWillUseSameFontAsWordAutomatically = sameFontIgnoringIrrelevantFields(*pSourceFont, *pDestFont);
3365  }
3366  }
3367 
3368  // Writer won't use the same font as word, so force the issue
3369  if (!bWriterWillUseSameFontAsWordAutomatically)
3370  {
3371  const SvxFontItem *pSourceFont = static_cast<const SvxFontItem*>(GetFormatAttr(nForceFromFontId));
3372 
3373  for (size_t i = 0; i < SAL_N_ELEMENTS(aIds); ++i)
3374  {
3375  const SvxFontItem *pDestFont = static_cast<const SvxFontItem*>(GetFormatAttr(aIds[i]));
3376  aForced[i] = aIds[i] != nForceFromFontId && *pSourceFont != *pDestFont;
3377  if (aForced[i])
3378  {
3379  pOverriddenItems[i] =
3380  static_cast<const SvxFontItem*>(m_xCtrlStck->GetStackAttr(*m_pPaM->GetPoint(), aIds[i]));
3381 
3382  SvxFontItem aForceFont(*pSourceFont);
3383  aForceFont.SetWhich(aIds[i]);
3384  m_xCtrlStck->NewAttr(*m_pPaM->GetPoint(), aForceFont);
3385  }
3386  }
3387  }
3388  }
3389 
3390  simpleAddTextToParagraph(sChunk);
3391 
3392  for (size_t i = 0; i < SAL_N_ELEMENTS(aIds); ++i)
3393  {
3394  if (aForced[i])
3395  {
3396  m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), aIds[i]);
3397  if (pOverriddenItems[i])
3398  m_xCtrlStck->NewAttr(*m_pPaM->GetPoint(), *(pOverriddenItems[i]));
3399  }
3400  }
3401 
3402  nPos = nEnd;
3403  if (nPos < nLen)
3404  nScript = lcl_getScriptType(xBI, rAddString, nPos);
3405  }
3406 }
3407 
3408 void SwWW8ImplReader::simpleAddTextToParagraph(const OUString& rAddString)
3409 {
3410  if (rAddString.isEmpty())
3411  return;
3412 
3413 #if OSL_DEBUG_LEVEL > 1
3414  SAL_INFO("sw.ww8", "<addTextToParagraph>" << rAddString << "</addTextToParagraph>");
3415 #endif
3416 
3417  const SwContentNode *pCntNd = m_pPaM->GetContentNode();
3418  const SwTextNode* pNd = pCntNd ? pCntNd->GetTextNode() : nullptr;
3419 
3420  OSL_ENSURE(pNd, "What the hell, where's my text node");
3421 
3422  if (!pNd)
3423  return;
3424 
3425  const sal_Int32 nCharsLeft = SAL_MAX_INT32 - pNd->GetText().getLength();
3426  if (nCharsLeft > 0)
3427  {
3428  if (rAddString.getLength() <= nCharsLeft)
3429  {
3431  }
3432  else
3433  {
3434  m_rDoc.getIDocumentContentOperations().InsertString(*m_pPaM, rAddString.copy(0, nCharsLeft));
3436  m_rDoc.getIDocumentContentOperations().InsertString(*m_pPaM, rAddString.copy(nCharsLeft));
3437  }
3438  }
3439  else
3440  {
3443  }
3444 
3445  m_bReadTable = false;
3446 }
3447 
3451 bool SwWW8ImplReader::ReadChars(WW8_CP& rPos, WW8_CP nNextAttr, long nTextEnd,
3452  long nCpOfs)
3453 {
3454  long nEnd = ( nNextAttr < nTextEnd ) ? nNextAttr : nTextEnd;
3455 
3456  if (m_bSymbol || m_bIgnoreText)
3457  {
3458  WW8_CP nRequested = nEnd - rPos;
3459  if (m_bSymbol) // Insert special chars
3460  {
3461  sal_uInt64 nMaxPossible = m_pStrm->remainingSize();
3462  if (static_cast<sal_uInt64>(nRequested) > nMaxPossible)
3463  {
3464  SAL_WARN("sw.ww8", "document claims to have more characters, " << nRequested << " than remaining, " << nMaxPossible);
3465  nRequested = nMaxPossible;
3466  }
3467 
3468  for (WW8_CP nCh = 0; nCh < nRequested; ++nCh)
3469  {
3471  }
3472  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_FONT );
3475  }
3476  m_pStrm->SeekRel(nRequested);
3477  rPos = nEnd; // Ignore until attribute end
3478  return false;
3479  }
3480 
3481  while (true)
3482  {
3483  if (ReadPlainChars(rPos, nEnd, nCpOfs))
3484  return false; // Done
3485 
3486  bool bStartLine = ReadChar(rPos, nCpOfs);
3487  rPos++;
3488  if (m_bPgSecBreak || bStartLine || rPos == nEnd) // CR or Done
3489  {
3490  return bStartLine;
3491  }
3492  }
3493 }
3494 
3496 {
3497  bool bParaEndAdded = false;
3498  // #i1909# section/page breaks should not occur in tables, word
3499  // itself ignores them in this case.
3500  if (!m_nInTable)
3501  {
3502  bool IsTemp=true;
3503  SwTextNode* pTemp = m_pPaM->GetNode().GetTextNode();
3504  if (pTemp && pTemp->GetText().isEmpty()
3506  {
3507  IsTemp = false;
3510  }
3511 
3512  m_bPgSecBreak = true;
3513  m_xCtrlStck->KillUnlockedAttrs(*m_pPaM->GetPoint());
3514  /*
3515  If it's a 0x0c without a paragraph end before it, act like a
3516  paragraph end, but nevertheless, numbering (and perhaps other
3517  similar constructs) do not exist on the para.
3518  */
3519  if (!m_bWasParaEnd && IsTemp)
3520  {
3521  bParaEndAdded = true;
3522  if (0 >= m_pPaM->GetPoint()->nContent.GetIndex())
3523  {
3524  if (SwTextNode* pTextNode = m_pPaM->GetNode().GetTextNode())
3525  {
3526  pTextNode->SetAttr(
3528  }
3529  }
3530  }
3531  }
3532  return bParaEndAdded;
3533 }
3534 
3535 bool SwWW8ImplReader::ReadChar(long nPosCp, long nCpOfs)
3536 {
3537  bool bNewParaEnd = false;
3538  // Reset Unicode flag and correct FilePos if needed.
3539  // Note: Seek is not expensive, as we're checking inline whether or not
3540  // the correct FilePos has already been reached.
3541  std::size_t nRequestedPos = m_xSBase->WW8Cp2Fc(nCpOfs+nPosCp, &m_bIsUnicode);
3542  if (!checkSeek(*m_pStrm, nRequestedPos))
3543  return false;
3544 
3545  sal_uInt8 nBCode(0);
3546  sal_uInt16 nWCharVal(0);
3547  if( m_bIsUnicode )
3548  m_pStrm->ReadUInt16( nWCharVal ); // unicode --> read 2 bytes
3549  else
3550  {
3551  m_pStrm -> ReadUChar( nBCode ); // old code --> read 1 byte
3552  nWCharVal = nBCode;
3553  }
3554 
3555  sal_Unicode cInsert = '\x0';
3556  bool bParaMark = false;
3557 
3558  if ( 0xc != nWCharVal )
3559  m_bFirstParaOfPage = false;
3560 
3561  switch (nWCharVal)
3562  {
3563  case 0:
3564  {
3565  // Page number
3566  SwPageNumberField aField(
3567  static_cast<SwPageNumberFieldType*>(m_rDoc.getIDocumentFieldsAccess().GetSysFieldType(
3570  }
3571  break;
3572  case 0xe:
3573  // if there is only one column word treats a column break like a pagebreak.
3575  bParaMark = HandlePageBreakChar();
3576  else if (!m_nInTable)
3577  {
3578  // Always insert a txtnode for a column break, e.g. ##
3579  SwContentNode *pCntNd=m_pPaM->GetContentNode();
3580  if (pCntNd!=nullptr && pCntNd->Len()>0) // if par is empty not break is needed
3583  }
3584  break;
3585  case 0x7:
3586  {
3587  bNewParaEnd = true;
3588  WW8PLCFxDesc* pPap = m_xPlcxMan->GetPap();
3589  //The last paragraph of each cell is terminated by a special
3590  //paragraph mark called a cell mark. Following the cell mark
3591  //that ends the last cell of a table row, the table row is
3592  //terminated by a special paragraph mark called a row mark
3593  //
3594  //So the 0x7 should be right at the end of the previous
3595  //range to be a real cell-end.
3596  if (pPap->nOrigStartPos == nPosCp+1 ||
3597  pPap->nOrigStartPos == WW8_CP_MAX)
3598  {
3599  TabCellEnd(); // Table cell/row end
3600  }
3601  else
3602  bParaMark = true;
3603  }
3604  break;
3605  case 0xf:
3606  if( !m_bSpec ) // "Satellite"
3607  cInsert = u'\x00a4';
3608  break;
3609  case 0x14:
3610  if( !m_bSpec ) // "Para End" char
3611  cInsert = u'\x00b5';
3612  //TODO: should this be U+00B6 PILCROW SIGN rather than
3613  // U+00B5 MICRO SIGN?
3614  break;
3615  case 0x15:
3616  if( !m_bSpec ) // Juristenparagraph
3617  {
3618  cp_set::iterator aItr = m_aTOXEndCps.find(static_cast<WW8_CP>(nPosCp));
3619  if (aItr == m_aTOXEndCps.end())
3620  cInsert = u'\x00a7';
3621  else
3622  m_aTOXEndCps.erase(aItr);
3623  }
3624  break;
3625  case 0x9:
3626  cInsert = '\x9'; // Tab
3627  break;
3628  case 0xb:
3629  cInsert = '\xa'; // Hard NewLine
3630  break;
3631  case 0xc:
3632  bParaMark = HandlePageBreakChar();
3633  break;
3634  case 0x1e: // Non-breaking hyphen
3636  break;
3637  case 0x1f: // Non-required hyphens
3639  break;
3640  case 0xa0: // Non-breaking spaces
3642  break;
3643  case 0x1:
3644  /*
3645  Current thinking is that if bObj is set then we have a
3646  straightforward "traditional" ole object, otherwise we have a
3647  graphic preview of an associated ole2 object (or a simple
3648  graphic of course)
3649 
3650  normally in the canvas field, the code is 0x8 0x1.
3651  in a special case, the code is 0x1 0x1, which yields a simple picture
3652  */
3653  {
3654  bool bReadObj = IsInlineEscherHack();
3655  if( bReadObj )
3656  {
3657  long nCurPos = m_pStrm->Tell();
3658  sal_uInt16 nWordCode(0);
3659 
3660  if( m_bIsUnicode )
3661  m_pStrm->ReadUInt16( nWordCode );
3662  else
3663  {
3664  sal_uInt8 nByteCode(0);
3665  m_pStrm->ReadUChar( nByteCode );
3666  nWordCode = nByteCode;
3667  }
3668  if( nWordCode == 0x1 )
3669  bReadObj = false;
3670  m_pStrm->Seek( nCurPos );
3671  }
3672  if( !bReadObj )
3673  {
3674  SwFrameFormat *pResult = nullptr;
3675  if (m_bObj)
3676  pResult = ImportOle();
3677  else if (m_bSpec)
3678  pResult = ImportGraf();
3679 
3680  // If we have a bad 0x1 insert a space instead.
3681  if (!pResult)
3682  {
3683  cInsert = ' ';
3684  OSL_ENSURE(!m_bObj && !m_bEmbeddObj && !m_nObjLocFc,
3685  "WW8: Please report this document, it may have a "
3686  "missing graphic");
3687  }
3688  else
3689  {
3690  // reset the flags.
3691  m_bObj = m_bEmbeddObj = false;
3692  m_nObjLocFc = 0;
3693  }
3694  }
3695  }
3696  break;
3697  case 0x8:
3698  if( !m_bObj )
3699  Read_GrafLayer( nPosCp );
3700  break;
3701  case 0xd:
3702  bNewParaEnd = bParaMark = true;
3703  if (m_nInTable > 1)
3704  {
3705  /*
3706  #i9666#/#i23161#
3707  Yes complex, if there is an entry in the undocumented PLCF
3708  which I believe to be a record of cell and row boundaries
3709  see if the magic bit which I believe to mean cell end is
3710  set. I also think btw that the third byte of the 4 byte
3711  value is the level of the cell
3712  */
3713  WW8PLCFspecial* pTest = m_xPlcxMan->GetMagicTables();
3714  if (pTest && pTest->SeekPosExact(nPosCp+1+nCpOfs) &&
3715  pTest->Where() == nPosCp+1+nCpOfs)
3716  {
3717  WW8_FC nPos;
3718  void *pData;
3719  sal_uInt32 nData = pTest->Get(nPos, pData) ? SVBT32ToUInt32(*static_cast<SVBT32*>(pData))
3720  : 0;
3721  if (nData & 0x2) // Might be how it works
3722  {
3723  TabCellEnd();
3724  bParaMark = false;
3725  }
3726  }
3727  // tdf#106799: We expect TTP marks to be also cell marks,
3728  // but sometimes sprmPFInnerTtp comes without sprmPFInnerTableCell
3729  else if (m_bWasTabCellEnd || m_bWasTabRowEnd)
3730  {
3731  TabCellEnd();
3732  bParaMark = false;
3733  }
3734  }
3735 
3736  m_bWasTabCellEnd = false;
3737 
3738  break; // line end
3739  case 0x5: // Annotation reference
3740  case 0x13:
3741  break;
3742  case 0x2: // TODO: Auto-Footnote-Number, should be replaced by SwWW8ImplReader::End_Footnote later
3743  if (!m_aFootnoteStack.empty())
3744  cInsert = 0x2;
3745  break;
3746  default:
3747  SAL_INFO( "sw.ww8.level2", "<unknownValue val=\"" << nWCharVal << "\">" );
3748  break;
3749  }
3750 
3751  if( '\x0' != cInsert )
3752  {
3753  OUString sInsert(cInsert);
3755  }
3756  if (!m_aApos.back()) // a para end in apo doesn't count
3757  m_bWasParaEnd = bNewParaEnd;
3758  return bParaMark;
3759 }
3760 
3762  bool* pStartAttr, bool bCallProcessSpecial)
3763 {
3764  sal_uInt16 nOldColl = m_nCurrentColl;
3765  m_nCurrentColl = m_xPlcxMan->GetColl();
3766 
3767  // Invalid Style-Id
3768  if (m_nCurrentColl >= m_vColl.size() || !m_vColl[m_nCurrentColl].m_pFormat || !m_vColl[m_nCurrentColl].m_bColl)
3769  {
3770  m_nCurrentColl = 0;
3771  m_bParaAutoBefore = false;
3772  m_bParaAutoAfter = false;
3773  }
3774  else
3775  {
3776  m_bParaAutoBefore = m_vColl[m_nCurrentColl].m_bParaAutoBefore;
3777  m_bParaAutoAfter = m_vColl[m_nCurrentColl].m_bParaAutoAfter;
3778  }
3779 
3780  if (nOldColl >= m_vColl.size())
3781  nOldColl = 0; // guess! TODO make sure this is what we want
3782 
3783  bool bTabRowEnd = false;
3784  if( pStartAttr && bCallProcessSpecial && !m_bInHyperlink )
3785  {
3786  bool bReSync;
3787  // Frame/Table/Autonumbering List Level
3788  bTabRowEnd = ProcessSpecial(bReSync, rRes.nCurrentCp + m_xPlcxMan->GetCpOfs());
3789  if( bReSync )
3790  *pStartAttr = m_xPlcxMan->Get( &rRes ); // Get Attribut-Pos again
3791  }
3792 
3793  if (!bTabRowEnd && StyleExists(m_nCurrentColl))
3794  {
3796  ChkToggleAttr(m_vColl[ nOldColl ].m_n81Flags, m_vColl[ m_nCurrentColl ].m_n81Flags);
3797  ChkToggleBiDiAttr(m_vColl[nOldColl].m_n81BiDiFlags,
3798  m_vColl[m_nCurrentColl].m_n81BiDiFlags);
3799  }
3800 }
3801 
3802 long SwWW8ImplReader::ReadTextAttr(WW8_CP& rTextPos, long nTextEnd, bool& rbStartLine, int nDepthGuard)
3803 {
3804  long nSkipChars = 0;
3805  WW8PLCFManResult aRes;
3806 
3807  OSL_ENSURE(m_pPaM->GetNode().GetTextNode(), "Missing txtnode");
3808  bool bStartAttr = m_xPlcxMan->Get(&aRes); // Get Attribute position again
3809  aRes.nCurrentCp = rTextPos; // Current Cp position
3810 
3811  bool bNewSection = (aRes.nFlags & MAN_MASK_NEW_SEP) && !m_bIgnoreText;
3812  if ( bNewSection ) // New Section
3813  {
3814  OSL_ENSURE(m_pPaM->GetNode().GetTextNode(), "Missing txtnode");
3815  // Create PageDesc and fill it
3816  m_aSectionManager.CreateSep(rTextPos);
3817  // -> 0xc was a Sectionbreak, but not a Pagebreak;
3818  // Create PageDesc and fill it
3819  m_bPgSecBreak = false;
3820  OSL_ENSURE(m_pPaM->GetNode().GetTextNode(), "Missing txtnode");
3821  }
3822 
3823  // New paragraph over Plcx.Fkp.papx
3824  if ( (aRes.nFlags & MAN_MASK_NEW_PAP)|| rbStartLine )
3825  {
3826  ProcessCurrentCollChange( aRes, &bStartAttr,
3828  !m_bIgnoreText );
3829  rbStartLine = false;
3830  }
3831 
3832  // position of last CP that's to be ignored
3833  long nSkipPos = -1;
3834 
3835  if( 0 < aRes.nSprmId ) // Ignore empty Attrs
3836  {
3837  if( ( eFTN > aRes.nSprmId ) || ( 0x0800 <= aRes.nSprmId ) )
3838  {
3839  if( bStartAttr ) // WW attributes
3840  {
3841  if( aRes.nMemLen >= 0 )
3842  ImportSprm(aRes.pMemPos, aRes.nMemLen, aRes.nSprmId);
3843  }
3844  else
3845  EndSprm( aRes.nSprmId ); // Switch off Attr
3846  }
3847  else if( aRes.nSprmId < 0x800 ) // Own helper attributes
3848  {
3849  if (bStartAttr)
3850  {
3851  nSkipChars = ImportExtSprm(&aRes);
3852  if (
3853  (aRes.nSprmId == eFTN) || (aRes.nSprmId == eEDN) ||
3854  (aRes.nSprmId == eFLD) || (aRes.nSprmId == eAND)
3855  )
3856  {
3857  WW8_CP nMaxLegalSkip = nTextEnd - rTextPos;
3858  // Skip Field/Footnote-/End-Note here
3859  rTextPos += std::min<WW8_CP>(nSkipChars, nMaxLegalSkip);
3860  nSkipPos = rTextPos-1;
3861  }
3862  }
3863  else
3864  EndExtSprm( aRes.nSprmId );
3865  }
3866  }
3867 
3868  sal_Int32 nRequestedPos = m_xSBase->WW8Cp2Fc(m_xPlcxMan->GetCpOfs() + rTextPos, &m_bIsUnicode);
3869  bool bValidPos = checkSeek(*m_pStrm, nRequestedPos);
3870  SAL_WARN_IF(!bValidPos, "sw.ww8", "Document claimed to have text at an invalid position, skip attributes for region");
3871 
3872  // Find next Attr position (and Skip attributes of field contents if needed)
3873  if (nSkipChars && !m_bIgnoreText)
3874  m_xCtrlStck->MarkAllAttrsOld();
3875  bool bOldIgnoreText = m_bIgnoreText;
3876  m_bIgnoreText = true;
3877  sal_uInt16 nOldColl = m_nCurrentColl;
3878  bool bDoPlcxManPlusPLus = true;
3879  long nNext;
3880  do
3881  {
3882  if( bDoPlcxManPlusPLus )
3883  m_xPlcxMan->advance();
3884  nNext = bValidPos ? m_xPlcxMan->Where() : nTextEnd;
3885 
3887  m_pPostProcessAttrsInfo->mnCpStart == nNext)
3888  {
3889  m_pPostProcessAttrsInfo->mbCopy = true;
3890  }
3891 
3892  if( (0 <= nNext) && (nSkipPos >= nNext) )
3893  {
3894  if (nDepthGuard >= 1024)
3895  {
3896  SAL_WARN("sw.ww8", "ReadTextAttr hit recursion limit");
3897  nNext = nTextEnd;
3898  }
3899  else
3900  nNext = ReadTextAttr(rTextPos, nTextEnd, rbStartLine, nDepthGuard + 1);
3901  bDoPlcxManPlusPLus = false;
3902  m_bIgnoreText = true;
3903  }
3904 
3906  nNext > m_pPostProcessAttrsInfo->mnCpEnd)
3907  {
3908  m_pPostProcessAttrsInfo->mbCopy = false;
3909  }
3910  }
3911  while( nSkipPos >= nNext );
3912  m_bIgnoreText = bOldIgnoreText;
3913  if( nSkipChars )
3914  {
3915  m_xCtrlStck->KillUnlockedAttrs( *m_pPaM->GetPoint() );
3916  if( nOldColl != m_xPlcxMan->GetColl() )
3917  ProcessCurrentCollChange(aRes, nullptr, false);
3918  }
3919 
3920  return nNext;
3921 }
3922 
3923 //Revised 2012.8.16 for the complex attribute presentation of 0x0D in MS
3924 bool SwWW8ImplReader::IsParaEndInCPs(sal_Int32 nStart, sal_Int32 nEnd,bool bSdOD) const
3925 {
3926  //Revised for performance consideration
3927  if (nStart == -1 || nEnd == -1 || nEnd < nStart )
3928  return false;
3929 
3930  return std::any_of(m_aEndParaPos.rbegin(), m_aEndParaPos.rend(),
3931  [=](const WW8_CP& rPos) {
3932  //Revised 2012.8.16,to the 0x0D,the attribute will have two situations
3933  //*********within***********exact******
3934  //*********but also sample with only left and the position of 0x0d is the edge of the right side***********
3935  return (bSdOD && ((nStart < rPos && nEnd > rPos) || (nStart == nEnd && rPos == nStart))) ||
3936  (!bSdOD && (nStart < rPos && nEnd >= rPos));
3937  }
3938  );
3939 }
3940 
3941 //Clear the para end position recorded in reader intermittently for the least impact on loading performance
3943 {
3944  if ( !m_aEndParaPos.empty() )
3945  m_aEndParaPos.clear();
3946 }
3947 
3948 void SwWW8ImplReader::ReadAttrs(WW8_CP& rTextPos, WW8_CP& rNext, long nTextEnd, bool& rbStartLine)
3949 {
3950  // Do we have attributes?
3951  if( rTextPos >= rNext )
3952  {
3953  do
3954  {
3955  m_aCurrAttrCP = rTextPos;
3956  rNext = ReadTextAttr(rTextPos, nTextEnd, rbStartLine);
3957  if (rTextPos == rNext && rTextPos >= nTextEnd)
3958  break;
3959  }
3960  while( rTextPos >= rNext );
3961 
3962  }
3963  else if ( rbStartLine )
3964  {
3965  /* No attributes, but still a new line.
3966  * If a line ends with a line break and paragraph attributes or paragraph templates
3967  * do NOT change the line end was not added to the Plcx.Fkp.papx i.e. (nFlags & MAN_MASK_NEW_PAP)
3968  * is false.
3969  * Due to this we need to set the template here as a kind of special treatment.
3970  */
3971  if (!m_bCpxStyle && m_nCurrentColl < m_vColl.size())
3973  rbStartLine = false;
3974  }
3975 }
3976 
3983 {
3984  // If there are any unclosed sprms then copy them to
3985  // another stack and close the ones that must be closed
3986  std::stack<sal_uInt16> aStack;
3987  m_xPlcxMan->TransferOpenSprms(aStack);
3988 
3989  while (!aStack.empty())
3990  {
3991  sal_uInt16 nSprmId = aStack.top();
3992  if ((0 < nSprmId) && (( eFTN > nSprmId) || (0x0800 <= nSprmId)))
3993  EndSprm(nSprmId);
3994  aStack.pop();
3995  }
3996 
3997  EndSpecial();
3998 }
3999 
4000 bool SwWW8ImplReader::ReadText(WW8_CP nStartCp, WW8_CP nTextLen, ManTypes nType)
4001 {
4002  bool bJoined=false;
4003 
4004  bool bStartLine = true;
4005  short nCrCount = 0;
4006  short nDistance = 0;
4007 
4008  m_bWasParaEnd = false;
4009  m_nCurrentColl = 0;
4010  m_xCurrentItemSet.reset();
4011  m_nCharFormat = -1;
4012  m_bSpec = false;
4013  m_bPgSecBreak = false;
4014 
4015  m_xPlcxMan.reset(new WW8PLCFMan(m_xSBase.get(), nType, nStartCp));
4016  long nCpOfs = m_xPlcxMan->GetCpOfs(); // Offset for Header/Footer, Footnote
4017 
4018  WW8_CP nNext = m_xPlcxMan->Where();
4019  m_pPreviousNode = nullptr;
4020  sal_uInt8 nDropLines = 0;
4021  SwCharFormat* pNewSwCharFormat = nullptr;
4022  const SwCharFormat* pFormat = nullptr;
4023 
4024  bool bValidPos = checkSeek(*m_pStrm, m_xSBase->WW8Cp2Fc(nStartCp + nCpOfs, &m_bIsUnicode));
4025  if (!bValidPos)
4026  return false;
4027 
4028  WW8_CP l = nStartCp;
4029  const WW8_CP nMaxPossible = WW8_CP_MAX-nStartCp;
4030  if (nTextLen > nMaxPossible)
4031  {
4032  SAL_WARN_IF(nTextLen > nMaxPossible, "sw.ww8", "TextLen too long");
4033  nTextLen = nMaxPossible;
4034  }
4035  WW8_CP nTextEnd = nStartCp+nTextLen;
4036  while (l < nTextEnd)
4037  {
4038  ReadAttrs( l, nNext, nTextEnd, bStartLine );// Takes SectionBreaks into account, too
4039  OSL_ENSURE(m_pPaM->GetNode().GetTextNode(), "Missing txtnode");
4040 
4041  if (m_pPostProcessAttrsInfo != nullptr)
4042  PostProcessAttrs();
4043 
4044  if (l >= nTextEnd)
4045  break;
4046 
4047  bStartLine = ReadChars(l, nNext, nTextEnd, nCpOfs);
4048 
4049  // If the previous paragraph was a dropcap then do not
4050  // create a new txtnode and join the two paragraphs together
4051  if (bStartLine && !m_pPreviousNode) // Line end
4052  {
4053  bool bSplit = true;
4055  {
4056  m_bCareFirstParaEndInToc = false;
4057  if (m_pPaM->End() && m_pPaM->End()->nNode.GetNode().GetTextNode() && m_pPaM->End()->nNode.GetNode().GetTextNode()->Len() == 0)
4058  bSplit = false;
4059  }
4061  {
4062  m_bCareLastParaEndInToc = false;
4063  if (m_pPaM->End() && m_pPaM->End()->nNode.GetNode().GetTextNode() && m_pPaM->End()->nNode.GetNode().GetTextNode()->Len() == 0)
4064  bSplit = false;
4065  }
4066  if (bSplit)
4067  {
4068  // We will record the CP of a paragraph end ('0x0D'), if current loading contents is from main stream;
4069  if (m_bOnLoadingMain)
4070  m_aEndParaPos.push_back(l-1);
4072  }
4073  }
4074 
4075  if (m_pPreviousNode && bStartLine)
4076  {
4077  SwTextNode* pEndNd = m_pPaM->GetNode().GetTextNode();
4078  const sal_Int32 nDropCapLen = m_pPreviousNode->GetText().getLength();
4079 
4080  // Need to reset the font size and text position for the dropcap
4081  {
4082  SwPaM aTmp(*pEndNd, 0, *pEndNd, nDropCapLen+1);
4083  m_xCtrlStck->Delete(aTmp);
4084  }
4085 
4086  // Get the default document dropcap which we can use as our template
4087  const SwFormatDrop* defaultDrop =
4088  static_cast<const SwFormatDrop*>( GetFormatAttr(RES_PARATR_DROP));
4089  SwFormatDrop aDrop(*defaultDrop);
4090 
4091  aDrop.GetLines() = nDropLines;
4092  aDrop.GetDistance() = nDistance;
4093  aDrop.GetChars() = writer_cast<sal_uInt8>(nDropCapLen);
4094  // Word has no concept of a "whole word dropcap"
4095  aDrop.GetWholeWord() = false;
4096 
4097  if (pFormat)
4098  aDrop.SetCharFormat(const_cast<SwCharFormat*>(pFormat));
4099  else if(pNewSwCharFormat)
4100  aDrop.SetCharFormat(pNewSwCharFormat);
4101 
4102  SwPosition aStart(*pEndNd);
4103  m_xCtrlStck->NewAttr(aStart, aDrop);
4104  m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_PARATR_DROP);
4105  m_pPreviousNode = nullptr;
4106  }
4107  else if (m_bDropCap)
4108  {
4109  // If we have found a dropcap store the textnode
4111 
4112  SprmResult aDCS;
4113  if (m_bVer67)
4114  aDCS = m_xPlcxMan->GetPapPLCF()->HasSprm(46);
4115  else
4116  aDCS = m_xPlcxMan->GetPapPLCF()->HasSprm(0x442C);
4117 
4118  if (aDCS.pSprm && aDCS.nRemainingData >= 1)
4119  nDropLines = (*aDCS.pSprm) >> 3;
4120  else // There is no Drop Cap Specifier hence no dropcap
4121  m_pPreviousNode = nullptr;
4122 
4123  SprmResult aDistance = m_xPlcxMan->GetPapPLCF()->HasSprm(0x842F);
4124  if (aDistance.pSprm && aDistance.nRemainingData >= 2)
4125  nDistance = SVBT16ToUInt16(aDistance.pSprm);
4126  else
4127  nDistance = 0;
4128 
4129  const SwFormatCharFormat *pSwFormatCharFormat = nullptr;
4130 
4131  if (m_xCurrentItemSet)
4132  pSwFormatCharFormat = &(ItemGet<SwFormatCharFormat>(*m_xCurrentItemSet, RES_TXTATR_CHARFMT));
4133 
4134  if (pSwFormatCharFormat)
4135  pFormat = pSwFormatCharFormat->GetCharFormat();
4136 
4137  if (m_xCurrentItemSet && !pFormat)
4138  {
4139  OUString sPrefix = "WW8Dropcap" + OUString::number(m_nDropCap++);
4140  pNewSwCharFormat = m_rDoc.MakeCharFormat(sPrefix, m_rDoc.GetDfltCharFormat());
4141  m_xCurrentItemSet->ClearItem(RES_CHRATR_ESCAPEMENT);
4142  pNewSwCharFormat->SetFormatAttr(*m_xCurrentItemSet);
4143  }
4144 
4145  m_xCurrentItemSet.reset();
4146  m_bDropCap=false;
4147  }
4148 
4149  if (bStartLine || m_bWasTabRowEnd)
4150  {
4151  // Call all 64 CRs; not for Header and the like
4152  if ((nCrCount++ & 0x40) == 0 && nType == MAN_MAINTEXT && l <= nTextLen)
4153  {
4154  if (nTextLen < WW8_CP_MAX/100)
4155  m_nProgress = static_cast<sal_uInt16>(l * 100 / nTextLen);
4156  else
4157  m_nProgress = static_cast<sal_uInt16>(l / nTextLen * 100);
4158  m_xProgress->Update(m_nProgress); // Update
4159  }
4160  }
4161 
4162  // If we have encountered a 0x0c which indicates either section of
4163  // pagebreak then look it up to see if it is a section break, and
4164  // if it is not then insert a page break. If it is a section break
4165  // it will be handled as such in the ReadAttrs of the next loop
4166  if (m_bPgSecBreak)
4167  {
4168  // We need only to see if a section is ending at this cp,
4169  // the plcf will already be sitting on the correct location
4170  // if it is there.
4171  WW8PLCFxDesc aTemp;
4172  aTemp.nStartPos = aTemp.nEndPos = WW8_CP_MAX;
4173  if (m_xPlcxMan->GetSepPLCF())
4174  m_xPlcxMan->GetSepPLCF()->GetSprms(&aTemp);
4175  if ((aTemp.nStartPos != l) && (aTemp.nEndPos != l))
4176  {
4177  // #i39251# - insert text node for page break, if no one inserted.
4178  // #i43118# - refine condition: the anchor
4179  // control stack has to have entries, otherwise it's not needed
4180  // to insert a text node.
4181  if (!bStartLine && !m_xAnchorStck->empty())
4182  {
4184  }
4186  SvxFormatBreakItem(SvxBreak::PageBefore, RES_BREAK));
4187  m_bFirstParaOfPage = true;
4188  m_bPgSecBreak = false;
4189  }
4190  }
4191  }
4192 
4193  m_pPreviousNode = nullptr;
4194 
4195  if (m_pPaM->GetPoint()->nContent.GetIndex())
4197 
4198  if (!m_bInHyperlink)
4199  bJoined = JoinNode(*m_pPaM);
4200 
4201  CloseAttrEnds();
4202 
4203  m_xPlcxMan.reset();
4204  return bJoined;
4205 }
4206 
4208  SvStream* pSt, SwDoc& rD, const OUString& rBaseURL, bool bNewDoc, bool bSkipImages, SwPosition const &rPos)
4209  : m_pDocShell(rD.GetDocShell())
4210  , m_pStg(pStorage)
4211  , m_pStrm(pSt)
4212  , m_pTableStream(nullptr)
4213  , m_pDataStream(nullptr)
4214  , m_rDoc(rD)
4215  , m_pPaM(nullptr)
4216  , m_aSectionManager(*this)
4217  , m_aExtraneousParas(rD)
4218  , m_aInsertedTables(rD)
4219  , m_aSectionNameGenerator(rD, "WW")
4220  , m_aGrfNameGenerator(bNewDoc, OUString('G'))
4221  , m_aParaStyleMapper(rD)
4222  , m_aCharStyleMapper(rD)
4223  , m_pFlyFormatOfJustInsertedGraphic(nullptr)
4224  , m_pFormatOfJustInsertedApo(nullptr)
4225  , m_pPreviousNumPaM(nullptr)
4226  , m_pPrevNumRule(nullptr)
4227  , m_aTextNodesHavingFirstLineOfstSet()
4228  , m_aTextNodesHavingLeftIndentSet()
4229  , m_pCurrentColl(nullptr)
4230  , m_pDfltTextFormatColl(nullptr)
4231  , m_pStandardFormatColl(nullptr)
4232  , m_pDrawModel(nullptr)
4233  , m_pDrawPg(nullptr)
4234  , m_pNumFieldType(nullptr)
4235  , m_sBaseURL(rBaseURL)
4236  , m_nIniFlags(0)
4237  , m_nIniFlags1(0)
4238  , m_nFieldFlags(0)
4239  , m_bRegardHindiDigits( false )
4240  , m_bDrawCpOValid( false )
4241  , m_nDrawCpO(0)
4242  , m_nPicLocFc(0)
4243  , m_nObjLocFc(0)
4244  , m_nIniFlyDx(0)
4245  , m_nIniFlyDy(0)
4246  , m_eTextCharSet(RTL_TEXTENCODING_ASCII_US)
4247  , m_eStructCharSet(RTL_TEXTENCODING_ASCII_US)
4248  , m_eHardCharSet(RTL_TEXTENCODING_DONTKNOW)
4249  , m_nProgress(0)
4250  , m_nCurrentColl(0)
4251  , m_nFieldNum(0)
4252  , m_nLFOPosition(USHRT_MAX)
4253  , m_nCharFormat(0)
4254  , m_nDrawXOfs(0)
4255  , m_nDrawYOfs(0)
4256  , m_nDrawXOfs2(0)
4257  , m_nDrawYOfs2(0)
4258  , m_cSymbol(0)
4259  , m_nWantedVersion(nVersionPara)
4260  , m_nSwNumLevel(0xff)
4261  , m_nWwNumType(0xff)
4262  , m_nListLevel(WW8ListManager::nMaxLevel)
4263  , m_bNewDoc(bNewDoc)
4264  , m_bSkipImages(bSkipImages)
4265  , m_bReadNoTable(false)
4266  , m_bPgSecBreak(false)
4267  , m_bSpec(false)
4268  , m_bObj(false)
4269  , m_bTxbxFlySection(false)
4270  , m_bHasBorder(false)
4271  , m_bSymbol(false)
4272  , m_bIgnoreText(false)
4273  , m_nInTable(0)
4274  , m_bWasTabRowEnd(false)
4275  , m_bWasTabCellEnd(false)
4276  , m_bAnl(false)
4277  , m_bHdFtFootnoteEdn(false)
4278  , m_bFootnoteEdn(false)
4279  , m_bIsHeader(false)
4280  , m_bIsFooter(false)
4281  , m_bIsUnicode(false)
4282  , m_bCpxStyle(false)
4283  , m_bStyNormal(false)
4284  , m_bWWBugNormal(false)
4285  , m_bNoAttrImport(false)
4286  , m_bInHyperlink(false)
4287  , m_bWasParaEnd(false)
4288  , m_bVer67(false)
4289  , m_bVer6(false)
4290  , m_bVer7(false)
4291  , m_bVer8(false)
4292  , m_bEmbeddObj(false)
4293  , m_bCurrentAND_fNumberAcross(false)
4294  , m_bNoLnNumYet(true)
4295  , m_bFirstPara(true)
4296  , m_bFirstParaOfPage(false)
4297  , m_bParaAutoBefore(false)
4298  , m_bParaAutoAfter(false)
4299  , m_bDropCap(false)
4300  , m_nDropCap(0)
4301  , m_bBidi(false)
4302  , m_bReadTable(false)
4303  , m_bLoadingTOXCache(false)
4304  , m_nEmbeddedTOXLevel(0)
4305  , m_bLoadingTOXHyperlink(false)
4306  , m_pPreviousNode(nullptr)
4307  , m_bCareFirstParaEndInToc(false)
4308  , m_bCareLastParaEndInToc(false)
4309  , m_aTOXEndCps()
4310  , m_aCurrAttrCP(-1)
4311  , m_bOnLoadingMain(false)
4312  , m_bNotifyMacroEventRead(false)
4313 {
4314  m_pStrm->SetEndian( SvStreamEndian::LITTLE );
4315  m_aApos.push_back(false);
4316 
4318 }
4319 
4321 {
4322 }
4323 
4324 void SwWW8ImplReader::DeleteStack(std::unique_ptr<SwFltControlStack> pStck)
4325 {
4326  if( pStck )
4327  {
4328  pStck->SetAttr( *m_pPaM->GetPoint(), 0, false);
4329  pStck->SetAttr( *m_pPaM->GetPoint(), 0, false);
4330  }
4331  else
4332  {
4333  OSL_ENSURE( false, "WW stack already deleted" );
4334  }
4335 }
4336 
4338  bool bIgnoreCols)
4339 {
4340  SwPageDesc &rPage = *rSection.mpPage;
4341 
4342  SetNumberingType(rSection, rPage);
4343 
4344  SwFrameFormat &rFormat = rPage.GetMaster();
4345 
4346  if(mrReader.m_xWDop->fUseBackGroundInAllmodes) // #i56806# Make sure mrReader is initialized
4347  mrReader.GrafikCtor();
4348 
4349  if (mrReader.m_xWDop->fUseBackGroundInAllmodes && mrReader.m_xMSDffManager)
4350  {
4351  tools::Rectangle aRect(0, 0, 100, 100); // A dummy, we don't care about the size
4352  SvxMSDffImportData aData(aRect);
4353  SdrObject* pObject = nullptr;
4354  if (mrReader.m_xMSDffManager->GetShape(0x401, pObject, aData) && !aData.empty())
4355  {
4356  // Only handle shape if it is a background shape
4357  if (aData.begin()->get()->nFlags & ShapeFlag::Background)
4358  {
4359  SfxItemSet aSet(rFormat.GetAttrSet());
4362  rFormat.SetFormatAttr(aSet.Get(RES_BACKGROUND));
4363  }
4364  }
4365  SdrObject::Free(pObject);
4366  }
4367  wwULSpaceData aULData;
4368  GetPageULData(rSection, aULData);
4369  SetPageULSpaceItems(rFormat, aULData, rSection);
4370 
4371  rPage.SetVerticalAdjustment( rSection.mnVerticalAdjustment );
4372 
4373  SetPage(rPage, rFormat, rSection, bIgnoreCols);
4374 
4375  if (!(rSection.maSep.pgbApplyTo & 1))
4376  SwWW8ImplReader::SetPageBorder(rFormat, rSection);
4377  if (!(rSection.maSep.pgbApplyTo & 2))
4379 
4380  mrReader.SetDocumentGrid(rFormat, rSection);
4381 }
4382 
4384 {
4385  bool bMirror = mrReader.m_xWDop->fMirrorMargins ||
4386  mrReader.m_xWDop->doptypography.m_f2on1;
4387 
4388  UseOnPage eUseBase = bMirror ? UseOnPage::Mirror : UseOnPage::All;
4389  UseOnPage eUse = eUseBase;
4390  if (!mrReader.m_xWDop->fFacingPages)
4392  if (!rSection.HasTitlePage())
4393  eUse |= UseOnPage::FirstShare;
4394 
4395  OSL_ENSURE(rSection.mpPage, "Makes no sense to call me with no pages to set");
4396  if (rSection.mpPage)
4397  rSection.mpPage->WriteUseOn(eUse);
4398 }
4399 
4404 static void GiveNodePageDesc(SwNodeIndex const &rIdx, const SwFormatPageDesc &rPgDesc,
4405  SwDoc &rDoc)
4406 {
4407  /*
4408  If it's a table here, apply the pagebreak to the table
4409  properties, otherwise we add it to the para at this
4410  position
4411  */
4412  if (rIdx.GetNode().IsTableNode())
4413  {
4414  SwTable& rTable =
4415  rIdx.GetNode().GetTableNode()->GetTable();
4416  SwFrameFormat* pApply = rTable.GetFrameFormat();
4417  OSL_ENSURE(pApply, "impossible");
4418  if (pApply)
4419  pApply->SetFormatAttr(rPgDesc);
4420  }
4421  else
4422  {
4423  SwPosition aPamStart(rIdx);
4424  aPamStart.nContent.Assign(
4425  rIdx.GetNode().GetContentNode(), 0);
4426  SwPaM aPage(aPamStart);
4427 
4428  rDoc.getIDocumentContentOperations().InsertPoolItem(aPage, rPgDesc);
4429  }
4430 }
4431 
4436  mySegIter const &rStart, bool bIgnoreCols)
4437 {
4438  if (mrReader.m_bNewDoc && rIter == rStart)
4439  {
4440  rIter->mpPage =
4442  }
4443  else
4444  {
4445  rIter->mpPage = mrReader.m_rDoc.MakePageDesc(
4447  nullptr, false);
4448  }
4449  OSL_ENSURE(rIter->mpPage, "no page!");
4450  if (!rIter->mpPage)
4451  return SwFormatPageDesc();
4452 
4453  // Set page before hd/ft
4454  const wwSection *pPrevious = nullptr;
4455  if (rIter != rStart)
4456  pPrevious = &(*(rIter-1));
4457  SetHdFt(*rIter, std::distance(rStart, rIter), pPrevious);
4458  SetUseOn(*rIter);
4459 
4460  // Set hd/ft after set page
4461  SetSegmentToPageDesc(*rIter, bIgnoreCols);
4462 
4463  SwFormatPageDesc aRet(rIter->mpPage);
4464 
4465  rIter->mpPage->SetFollow(rIter->mpPage);
4466 
4467  if (rIter->PageRestartNo())
4468  aRet.SetNumOffset(rIter->PageStartAt());
4469 
4470  ++mnDesc;
4471  return aRet;
4472 }
4473 
4475 {
4476  mySegIter aEnd = maSegments.end();
4477  mySegIter aStart = maSegments.begin();
4478  for (mySegIter aIter = aStart; aIter != aEnd; ++aIter)
4479  {
4480  // If the section is of type "New column" (0x01), then simply insert a column break.
4481  // But only if there actually are columns on the page, otherwise a column break
4482  // seems to be handled like a page break by MSO.
4483  if ( aIter->maSep.bkc == 1 && aIter->maSep.ccolM1 > 0 )
4484  {
4485  SwPaM start( aIter->maStart );
4487  continue;
4488  }
4489 
4490  mySegIter aNext = aIter+1;
4491  mySegIter aPrev = (aIter == aStart) ? aIter : aIter-1;
4492 
4493  // If two following sections are different in following properties, Word will interpret a continuous
4494  // section break between them as if it was a section break next page.
4495  bool bThisAndPreviousAreCompatible = ((aIter->GetPageWidth() == aPrev->GetPageWidth()) &&
4496  (aIter->GetPageHeight() == aPrev->GetPageHeight()) && (aIter->IsLandScape() == aPrev->IsLandScape()));
4497 
4498  bool bInsertSection = (aIter != aStart) && aIter->IsContinuous() && bThisAndPreviousAreCompatible;
4499  bool bInsertPageDesc = !bInsertSection;
4500  // HACK Force new pagedesc if margins change, otherwise e.g. floating tables may be anchored improperly.
4501  if( aIter->maSep.dyaTop != aPrev->maSep.dyaTop || aIter->maSep.dyaBottom != aPrev->maSep.dyaBottom
4502  || aIter->maSep.dxaLeft != aPrev->maSep.dxaLeft || aIter->maSep.dxaRight != aPrev->maSep.dxaRight )
4503  bInsertPageDesc = true;
4504  bool bProtected = SectionIsProtected(*aIter); // do we really need this ?? I guess I have a different logic in editshell which disables this...
4505 
4506  if (bInsertPageDesc)
4507  {
4508  /*
4509  If a cont section follows this section then we won't be
4510  creating a page desc with 2+ cols as we cannot host a one
4511  col section in a 2+ col pagedesc and make it look like
4512  word. But if the current section actually has columns then
4513  we are forced to insert a section here as well as a page
4514  descriptor.
4515  */
4516 
4517  bool bIgnoreCols = bInsertSection;
4518  bool bThisAndNextAreCompatible = (aNext == aEnd) ||
4519  ((aIter->GetPageWidth() == aNext->GetPageWidth()) &&
4520  (aIter->GetPageHeight() == aNext->GetPageHeight()) &&
4521  (aIter->IsLandScape() == aNext->IsLandScape()));
4522 
4523  if ((aNext != aEnd && aNext->IsContinuous() && bThisAndNextAreCompatible) || bProtected)
4524  {
4525  bIgnoreCols = true;
4526  if ((aIter->NoCols() > 1) || bProtected)
4527  bInsertSection = true;
4528  }
4529 
4530  SwFormatPageDesc aDesc(SetSwFormatPageDesc(aIter, aStart, bIgnoreCols));
4531  if (!aDesc.GetPageDesc())
4532  continue;
4533 
4534  // special case handling for odd/even section break
4535  // a) as before create a new page style for the section break
4536  // b) set Layout of generated page style to right/left ( according
4537  // to section break odd/even )
4538  // c) create a new style to follow the break page style
4539  if ( aIter->maSep.bkc == 3 || aIter->maSep.bkc == 4 )
4540  {
4541  // SetSwFormatPageDesc calls some methods that could
4542  // modify aIter (e.g. wwSection ).
4543  // Since we call SetSwFormatPageDesc below to generate the
4544  // 'Following' style of the Break style, it is safer
4545  // to take a copy of the contents of aIter.
4546  wwSection aTmpSection = *aIter;
4547  // create a new following page style
4548  SwFormatPageDesc aFollow(SetSwFormatPageDesc(aIter, aStart, bIgnoreCols));
4549  // restore any contents of aIter trashed by SetSwFormatPageDesc
4550  *aIter = aTmpSection;
4551 
4552  // Handle the section break
4553  UseOnPage eUseOnPage = UseOnPage::Left;
4554  if ( aIter->maSep.bkc == 4 ) // Odd ( right ) Section break
4555  eUseOnPage = UseOnPage::Right;
4556 
4557  // Keep the share flags.
4558  aDesc.GetPageDesc()->SetUseOn( eUseOnPage );
4559  aDesc.GetPageDesc()->SetFollow( aFollow.GetPageDesc() );
4560  }
4561 
4562  GiveNodePageDesc(aIter->maStart, aDesc, mrReader.m_rDoc);
4563  }
4564 
4565  SwTextNode* pTextNd = nullptr;
4566  if (bInsertSection)
4567  {
4568  // Start getting the bounds of this section
4569  SwPaM aSectPaM(*mrReader.m_pPaM, mrReader.m_pPaM);
4570  SwNodeIndex aAnchor(aSectPaM.GetPoint()->nNode);
4571  if (aNext != aEnd)
4572  {
4573  aAnchor = aNext->maStart;
4574  aSectPaM.GetPoint()->nNode = aAnchor;
4575  aSectPaM.GetPoint()->nContent.Assign(
4576  aNext->maStart.GetNode().GetContentNode(), 0);
4577  aSectPaM.Move(fnMoveBackward);
4578  }
4579 
4580  const SwPosition* pPos = aSectPaM.GetPoint();
4581  SwTextNode const*const pSttNd = pPos->nNode.GetNode().GetTextNode();
4582  const SwTableNode* pTableNd = pSttNd ? pSttNd->FindTableNode() : nullptr;
4583  if (pTableNd)
4584  {
4585  pTextNd =
4588 
4589  aSectPaM.GetPoint()->nNode.Assign(*pTextNd);
4590  aSectPaM.GetPoint()->nContent.Assign(
4591  aSectPaM.GetContentNode(), 0);
4592  }
4593 
4594  aSectPaM.SetMark();
4595 
4596  aSectPaM.GetPoint()->nNode = aIter->maStart;
4597  aSectPaM.GetPoint()->nContent.Assign(
4598  aSectPaM.GetContentNode(), 0);
4599 
4600  bool bHasOwnHdFt = false;
4601  /*
4602  In this nightmare scenario the continuous section has its own
4603  headers and footers so we will try and find a hard page break
4604  between here and the end of the section and put the headers and
4605  footers there.
4606  */
4607  if (!bInsertPageDesc)
4608  {
4609  bHasOwnHdFt =
4611  aIter->maSep.grpfIhdt & ~(WW8_HEADER_FIRST | WW8_FOOTER_FIRST),
4612  aIter->maSep.grpfIhdt, std::distance(aStart, aIter)
4613  );
4614  }
4615  if (bHasOwnHdFt)
4616  {
4617  // #i40766# Need to cache the page descriptor in case there is
4618  // no page break in the section
4619  SwPageDesc *pOrig = aIter->mpPage;
4620  bool bFailed = true;
4621  SwFormatPageDesc aDesc(SetSwFormatPageDesc(aIter, aStart, true));
4622  if (aDesc.GetPageDesc())
4623  {
4624  sal_uLong nStart = aSectPaM.Start()->nNode.GetIndex();
4625  sal_uLong nEnd = aSectPaM.End()->nNode.GetIndex();
4626  for(; nStart <= nEnd; ++nStart)
4627  {
4628  SwNode* pNode = mrReader.m_rDoc.GetNodes()[nStart];
4629  if (!pNode)
4630  continue;
4631  if (sw::util::HasPageBreak(*pNode))
4632  {
4633  SwNodeIndex aIdx(*pNode);
4634  GiveNodePageDesc(aIdx, aDesc, mrReader.m_rDoc);
4635  bFailed = false;
4636  break;
4637  }
4638  }
4639  }
4640  if(bFailed)
4641  {
4642  aIter->mpPage = pOrig;
4643  }
4644  }
4645 
4646  // End getting the bounds of this section, quite a job eh?
4647  SwSectionFormat *pRet = InsertSection(aSectPaM, *aIter);
4648  // The last section if continuous is always unbalanced
4649  if (pRet)
4650  {
4651  // Set the columns to be UnBalanced if that compatibility option is set
4652  if (mrReader.m_xWDop->fNoColumnBalance)
4654  else
4655  {
4656  // Otherwise set to unbalanced if the following section is
4657  // not continuous, (which also means that the last section
4658  // is unbalanced)
4659  if (aNext == aEnd || !aNext->IsContinuous())
4661  }
4662  }
4663  }
4664 
4665  if (pTextNd)
4666  {
4667  SwNodeIndex aIdx(*pTextNd);
4668  SwPaM aTest(aIdx);
4670  pTextNd = nullptr;
4671  }
4672  }
4673 }
4674 
4676 {
4677  auto aEnd = m_aTextNodes.rend();
4678  for (auto aI = m_aTextNodes.rbegin(); aI != aEnd; ++aI)
4679  {
4680  SwTextNode *pTextNode = *aI;
4681  SwNodeIndex aIdx(*pTextNode);
4682  SwPaM aTest(aIdx);
4684  }
4685  m_aTextNodes.clear();
4686 }
4687 
4689 {
4690  if (m_xWwFib->m_lcbCmds)
4691  {
4692  bool bValidPos = checkSeek(*m_pTableStream, m_xWwFib->m_fcCmds);
4693  if (!bValidPos)
4694  return;
4695 
4696  uno::Reference < embed::XStorage > xRoot(m_pDocShell->GetStorage());
4697 
4698  if (!xRoot.is())
4699  return;
4700 
4701  try
4702  {
4703  uno::Reference < io::XStream > xStream =
4704  xRoot->openStreamElement( SL::aMSMacroCmds, embed::ElementModes::READWRITE );
4705  std::unique_ptr<SvStream> xOutStream(::utl::UcbStreamHelper::CreateStream(xStream));
4706 
4707  sal_uInt32 lcbCmds = std::min<sal_uInt32>(m_xWwFib->m_lcbCmds, m_pTableStream->remainingSize());
4708  std::unique_ptr<sal_uInt8[]> xBuffer(new sal_uInt8[lcbCmds]);
4709  m_xWwFib->m_lcbCmds = m_pTableStream->ReadBytes(xBuffer.get(), lcbCmds);
4710  xOutStream->WriteBytes(xBuffer.get(), m_xWwFib->m_lcbCmds);
4711  }
4712  catch (...)
4713  {
4714  }
4715  }
4716 }
4717 
4719 {
4720  std::vector<OUString> aDocVarStrings;
4721  std::vector<ww::bytes> aDocVarStringIds;
4722  std::vector<OUString> aDocValueStrings;
4723  WW8ReadSTTBF(!m_bVer67, *m_pTableStream, m_xWwFib->m_fcStwUser,
4724  m_xWwFib->m_lcbStwUser, m_bVer67 ? 2 : 0, m_eStructCharSet,
4725  aDocVarStrings, &aDocVarStringIds, &aDocValueStrings);
4726  if (!m_bVer67) {
4727  uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
4728  m_pDocShell->GetModel(), uno::UNO_QUERY_THROW);
4729  uno::Reference<document::XDocumentProperties> xDocProps(
4730  xDPS->getDocumentProperties());
4731  OSL_ENSURE(xDocProps.is(), "DocumentProperties is null");
4732  uno::Reference<beans::XPropertyContainer> xUserDefinedProps =
4733  xDocProps->getUserDefinedProperties();
4734  OSL_ENSURE(xUserDefinedProps.is(), "UserDefinedProperties is null");
4735 
4736  for(size_t i=0; i<aDocVarStrings.size(); i++)
4737  {
4738  const OUString &rName = aDocVarStrings[i];
4739  uno::Any aValue;
4740  aValue <<= rName;
4741  try {
4742  xUserDefinedProps->addProperty( rName,
4743  beans::PropertyAttribute::REMOVABLE,
4744  aValue );
4745  } catch (const uno::Exception &) {
4746  // ignore
4747  }
4748  }
4749  }
4750 }
4751 
4756 {
4757  if( m_pStg )
4758  {
4759  uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
4760  m_pDocShell->GetModel(), uno::UNO_QUERY_THROW);
4761  uno::Reference<document::XDocumentProperties> xDocProps(
4762  xDPS->getDocumentProperties());
4763  OSL_ENSURE(xDocProps.is(), "DocumentProperties is null");
4764 
4765  if (xDocProps.is())
4766  {
4767  if ( m_xWwFib->m_fDot )
4768  {
4769  OUString sTemplateURL;
4770  SfxMedium* pMedium = m_pDocShell->GetMedium();
4771  if ( pMedium )
4772  {
4773  const OUString& aName = pMedium->GetName();
4774  INetURLObject aURL( aName );
4776  if ( !sTemplateURL.isEmpty() )
4777  xDocProps->setTemplateURL( sTemplateURL );
4778  }
4779  }
4780  else if (m_xWwFib->m_lcbSttbfAssoc) // not a template, and has a SttbfAssoc
4781  {
4782  auto nCur = m_pTableStream->Tell();
4783  Sttb aSttb;
4784  // point at tgc record
4785  if (!checkSeek(*m_pTableStream, m_xWwFib->m_fcSttbfAssoc) || !aSttb.Read(*m_pTableStream))
4786  SAL_WARN("sw.ww8", "** Read of SttbAssoc data failed!!!! ");
4787  m_pTableStream->Seek( nCur ); // return to previous position, is that necessary?
4788  OUString sPath = aSttb.getStringAtIndex( 0x1 );
4789  OUString aURL;
4790  // attempt to convert to url (won't work for obvious reasons on linux)
4791  if ( !sPath.isEmpty() )
4792  osl::FileBase::getFileURLFromSystemPath( sPath, aURL );
4793  if (aURL.isEmpty())
4794  xDocProps->setTemplateURL( aURL );
4795  else
4796  xDocProps->setTemplateURL( sPath );
4797 
4798  }
4799  sfx2::LoadOlePropertySet(xDocProps, m_pStg);
4800  }
4801  }
4802 }
4803 
4804 static void lcl_createTemplateToProjectEntry( const uno::Reference< container::XNameContainer >& xPrjNameCache, const OUString& sTemplatePathOrURL, const OUString& sVBAProjName )
4805 {
4806  if ( xPrjNameCache.is() )
4807  {
4808  INetURLObject aObj;
4809  aObj.SetURL( sTemplatePathOrURL );
4810  bool bIsURL = aObj.GetProtocol() != INetProtocol::NotValid;
4811  OUString aURL;
4812  if ( bIsURL )
4813  aURL = sTemplatePathOrURL;
4814  else
4815  {
4816  osl::FileBase::getFileURLFromSystemPath( sTemplatePathOrURL, aURL );
4817  aObj.SetURL( aURL );
4818  }
4819  try
4820  {
4821  OUString templateNameWithExt = aObj.GetLastName();
4822  OUString templateName;
4823  sal_Int32 nIndex = templateNameWithExt.lastIndexOf( '.' );
4824  if ( nIndex != -1 )
4825  {
4826  templateName = templateNameWithExt.copy( 0, nIndex );
4827  xPrjNameCache->insertByName( templateName, uno::makeAny( sVBAProjName ) );
4828  }
4829  }
4830  catch( const uno::Exception& )
4831  {
4832  }
4833  }
4834 }
4835 
4837 {
4840 public:
4841  WW8Customizations( SvStream*, WW8Fib const & );
4842  void Import( SwDocShell* pShell );
4843 };
4844 
4845 WW8Customizations::WW8Customizations( SvStream* pTableStream, WW8Fib const & rFib ) : mpTableStream(pTableStream), mWw8Fib( rFib )
4846 {
4847 }
4848 
4850 {
4852  return;
4853  try
4854  {
4855  Tcg aTCG;
4856  long nCur = mpTableStream->Tell();
4857  if (!checkSeek(*mpTableStream, mWw8Fib.m_fcCmds)) // point at tgc record
4858  {
4859  SAL_WARN("sw.ww8", "** Seek to Customization data failed!!!! ");
4860  return;
4861  }
4862  bool bReadResult = aTCG.Read( *mpTableStream );
4863  mpTableStream->Seek( nCur ); // return to previous position, is that necessary?
4864  if ( !bReadResult )
4865  {
4866  SAL_WARN("sw.ww8", "** Read of Customization data failed!!!! ");
4867  return;
4868  }
4869  aTCG.ImportCustomToolBar( *pShell );
4870  }
4871  catch(...)
4872  {
4873  SAL_WARN("sw.ww8", "** Read of Customization data failed!!!! epically");
4874  }
4875 }
4876 
4877 void SwWW8ImplReader::ReadGlobalTemplateSettings( const OUString& sCreatedFrom, const uno::Reference< container::XNameContainer >& xPrjNameCache )
4878 {
4880  return;
4881 
4882  SvtPathOptions aPathOpt;
4883  const OUString& aAddinPath = aPathOpt.GetAddinPath();
4884  uno::Sequence< OUString > sGlobalTemplates;
4885 
4886  // first get the autoload addins in the directory STARTUP
4887  uno::Reference<ucb::XSimpleFileAccess3> xSFA(ucb::SimpleFileAccess::create(::comphelper::getProcessComponentContext()));
4888 
4889  if( xSFA->isFolder( aAddinPath ) )
4890  sGlobalTemplates = xSFA->getFolderContents( aAddinPath, false );
4891 
4892  for ( const auto& rGlobalTemplate : std::as_const(sGlobalTemplates) )
4893  {
4894  INetURLObject aObj;
4895  aObj.SetURL( rGlobalTemplate );
4896  bool bIsURL = aObj.GetProtocol() != INetProtocol::NotValid;
4897  OUString aURL;
4898  if ( bIsURL )
4899  aURL = rGlobalTemplate;
4900  else
4901  osl::FileBase::getFileURLFromSystemPath( rGlobalTemplate, aURL );
4902  if ( !aURL.endsWithIgnoreAsciiCase( ".dot" ) || ( !sCreatedFrom.isEmpty() && sCreatedFrom == aURL ) )
4903  continue; // don't try and read the same document as ourselves
4904 
4905  tools::SvRef<SotStorage> rRoot = new SotStorage( aURL, StreamMode::STD_READWRITE );
4906 
4907  BasicProjImportHelper aBasicImporter( *m_pDocShell );
4908  // Import vba via oox filter
4909  aBasicImporter.import( m_pDocShell->GetMedium()->GetInputStream() );
4910  lcl_createTemplateToProjectEntry( xPrjNameCache, aURL, aBasicImporter.getProjectName() );
4911  // Read toolbars & menus
4912  tools::SvRef<SotStorageStream> refMainStream = rRoot->OpenSotStream( "WordDocument");
4913  refMainStream->SetEndian(SvStreamEndian::LITTLE);
4914  WW8Fib aWwFib( *refMainStream, 8 );
4915  tools::SvRef<SotStorageStream> xTableStream =
4916  rRoot->OpenSotStream(aWwFib.m_fWhichTableStm ? SL::a1Table : SL::a0Table, StreamMode::STD_READ);
4917 
4918  if (xTableStream.is() && ERRCODE_NONE == xTableStream->GetError())
4919  {
4920  xTableStream->SetEndian(SvStreamEndian::LITTLE);
4921  WW8Customizations aGblCustomisations( xTableStream.get(), aWwFib );
4922  aGblCustomisations.Import( m_pDocShell );
4923  }
4924  }
4925 }
4926 
4928 {
4930  if (m_bNewDoc && m_pStg && !pGloss)
4931  {
4932  // Initialize RDF metadata, to be able to add statements during the import.
4933  try
4934  {
4935  uno::Reference<frame::XModel> const xModel(m_rDoc.GetDocShell()->GetBaseModel());
4936  uno::Reference<rdf::XDocumentMetadataAccess> xDocumentMetadataAccess(xModel, uno::UNO_QUERY_THROW);
4937  uno::Reference<uno::XComponentContext> xComponentContext(comphelper::getProcessComponentContext());
4938  uno::Reference<embed::XStorage> xStorage = comphelper::OStorageHelper::GetTemporaryStorage();
4939  const uno::Reference<rdf::XURI> xBaseURI(sfx2::createBaseURI(xComponentContext, xModel, m_sBaseURL));
4940  uno::Reference<task::XInteractionHandler> xHandler;
4941  xDocumentMetadataAccess->loadMetadataFromStorage(xStorage, xBaseURI, xHandler);
4942  }
4943  catch (const uno::Exception&)
4944  {
4945  DBG_UNHANDLED_EXCEPTION("sw.ww8", "failed to initialize RDF metadata");
4946  }
4947  ReadDocInfo();
4948  }
4949 
4950  ::ww8::WW8FibData * pFibData = new ::ww8::WW8FibData();
4951 
4952  if (m_xWwFib->m_fReadOnlyRecommended)
4953  pFibData->setReadOnlyRecommended(true);
4954  else
4955  pFibData->setReadOnlyRecommended(false);
4956 
4957  if (m_xWwFib->m_fWriteReservation)
4958  pFibData->setWriteReservation(true);
4959  else
4960  pFibData->setWriteReservation(false);
4961 
4962  ::sw::tExternalDataPointer pExternalFibData(pFibData);
4963 
4965 
4966  ::sw::tExternalDataPointer pSttbfAsoc
4967  (new ::ww8::WW8Sttb<ww8::WW8Struct>(*m_pTableStream, m_xWwFib->m_fcSttbfAssoc, m_xWwFib->m_lcbSttbfAssoc));
4968 
4970 
4971  if (m_xWwFib->m_fWriteReservation || m_xWwFib->m_fReadOnlyRecommended)
4972  {
4973  SwDocShell * pDocShell = m_rDoc.GetDocShell();
4974  if (pDocShell)
4975  pDocShell->SetReadOnlyUI();
4976  }
4977 
4978  m_pPaM = mpCursor.get();
4979 
4981 
4983 
4984  /*
4985  RefFieldStck: Keeps track of bookmarks which may be inserted as
4986  variables instead.
4987  */
4990 
4992 
4993  size_t nPageDescOffset = m_rDoc.GetPageDescCnt();
4994 
4995  SwNodeIndex aSttNdIdx( m_rDoc.GetNodes() );
4996  SwRelNumRuleSpaces aRelNumRule(m_rDoc, m_bNewDoc);
4997 
4999 
5000  m_xSprmParser.reset(new wwSprmParser(*m_xWwFib));
5001 
5002  // Set handy helper variables
5003  m_bVer6 = (6 == m_xWwFib->m_nVersion);
5004  m_bVer7 = (7 == m_xWwFib->m_nVersion);
5005  m_bVer67 = m_bVer6 || m_bVer7;
5006  m_bVer8 = (8 == m_xWwFib->m_nVersion);
5007 
5009  m_eStructCharSet = WW8Fib::GetFIBCharset(m_xWwFib->m_chseTables, m_xWwFib->m_lid);
5010 
5011  m_bWWBugNormal = m_xWwFib->m_nProduct == 0xc03d;
5012 
5013  if (!m_bNewDoc)
5014  aSttNdIdx = m_pPaM->GetPoint()->nNode;
5015 
5016  m_xProgress.reset(new ImportProgress(m_pDocShell, 0, 100));
5017 
5018  // read Font Table
5019  m_xFonts.reset(new WW8Fonts(*m_pTableStream, *m_xWwFib));
5020 
5021  // Document Properties
5022  m_xWDop.reset(new WW8Dop(*m_pTableStream, m_xWwFib->m_nFib, m_xWwFib->m_fcDop,
5023  m_xWwFib->m_lcbDop));
5024 
5025  if (m_bNewDoc)
5026  ImportDop();
5027 
5028  /*
5029  Import revisioning data: author names
5030  */
5031  if( m_xWwFib->m_lcbSttbfRMark )
5032  {
5034  m_xWwFib->m_fcSttbfRMark,
5035  m_xWwFib->m_lcbSttbfRMark, m_rDoc);
5036  }
5037 
5038  // Initialize our String/ID map for Linked Sections
5039  std::vector<OUString> aLinkStrings;
5040  std::vector<ww::bytes> aStringIds;
5041 
5042  WW8ReadSTTBF(!m_bVer67, *m_pTableStream, m_xWwFib->m_fcSttbFnm,
5043  m_xWwFib->m_lcbSttbFnm, m_bVer67 ? 2 : 0, m_eStructCharSet,
5044  aLinkStrings, &aStringIds);
5045 
5046  for (size_t i=0; i < aLinkStrings.size() && i < aStringIds.size(); ++i)
5047  {
5048  const ww::bytes& stringId = aStringIds[i];
5049  if (stringId.size() < sizeof(WW8_STRINGID))
5050  {
5051  SAL_WARN("sw.ww8", "SwWW8ImplReader::CoreLoad: WW8_STRINGID is too short");
5052  continue;
5053  }
5054  const WW8_STRINGID *stringIdStruct = reinterpret_cast<const WW8_STRINGID*>(stringId.data());
5055  m_aLinkStringMap[SVBT16ToUInt16(stringIdStruct->nStringId)] = aLinkStrings[i];
5056  }
5057 
5058  ReadDocVars(); // import document variables as meta information.
5059 
5060  m_xProgress->Update(m_nProgress); // Update
5061 
5062