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