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