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