1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <config_features.h>
22 #include <sal/config.h>
23 #include <sal/log.hxx>
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 #include <com/sun/star/text/XTextFieldsSupplier.hpp>
32 #include <i18nlangtag/languagetag.hxx>
34 #include <comphelper/configuration.hxx>
35 #include <comphelper/string.hxx>
36 #include <unotools/ucbstreamhelper.hxx>
37 #include <unotools/streamwrap.hxx>
38 #include <rtl/random.h>
39 #include <rtl/ustring.hxx>
40 #include <rtl/ustrbuf.hxx>
42 #include <sfx2/docinf.hxx>
43 #include <sfx2/frame.hxx>
44 #include <sfx2/zoomitem.hxx>
45 #include <tools/urlobj.hxx>
46 #include <unotools/tempfile.hxx>
48 #include <comphelper/docpasswordrequest.hxx>
49 #include <comphelper/documentinfo.hxx>
50 #include <comphelper/propertysequence.hxx>
52 #include <editeng/outlobj.hxx>
53 #include <editeng/brushitem.hxx>
54 #include <editeng/formatbreakitem.hxx>
55 #include <editeng/tstpitem.hxx>
56 #include <editeng/ulspitem.hxx>
57 #include <editeng/langitem.hxx>
58 #include <editeng/opaqitem.hxx>
59 #include <editeng/charhiddenitem.hxx>
60 #include <editeng/fontitem.hxx>
61 #include <editeng/editeng.hxx>
62 #include <svx/svdoole2.hxx>
63 #include <svx/svdoashp.hxx>
64 #include <svx/svxerr.hxx>
65 #include <filter/msfilter/mscodec.hxx>
66 #include <svx/svdmodel.hxx>
67 #include <svx/xflclit.hxx>
68 #include <svx/sdasitm.hxx>
69 #include <svx/sdtagitm.hxx>
70 #include <svx/sdtcfitm.hxx>
71 #include <svx/sdtditm.hxx>
72 #include <svx/sdtmfitm.hxx>
75 #include <fmtinfmt.hxx>
77 #include <fmthdft.hxx>
78 #include <fmtcntnt.hxx>
79 #include <fmtcnct.hxx>
80 #include <fmtanchr.hxx>
81 #include <fmtpdsc.hxx>
82 #include <ftninfo.hxx>
86 #include <pagedesc.hxx>
88 #include <poolfmt.hxx>
89 #include <fmtclbl.hxx>
90 #include <section.hxx>
92 #include <IDocumentFieldsAccess.hxx>
93 #include <IDocumentLayoutAccess.hxx>
94 #include <IDocumentMarkAccess.hxx>
95 #include <IDocumentStylePoolAccess.hxx>
96 #include <IDocumentExternalData.hxx>
97 #include <../../core/inc/DocumentRedlineManager.hxx>
98 #include <docufld.hxx>
99 #include <swfltopt.hxx>
101 #include <viewsh.hxx>
102 #include <shellres.hxx>
104 #include <swtable.hxx>
105 #include <fchrfmt.hxx>
106 #include <charfmt.hxx>
107 #include <fmtautofmt.hxx>
108 #include <IDocumentSettingAccess.hxx>
109 #include "sprmids.hxx"
111 #include "writerwordglue.hxx"
114 #include <editeng/editids.hrc>
115 #include <fmtflcnt.hxx>
116 #include <txatbase.hxx>
118 #include "ww8par2.hxx"
120 #include <com/sun/star/beans/PropertyAttribute.hpp>
121 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
122 #include <com/sun/star/document/XViewDataSupplier.hpp>
124 #include <svl/lngmisc.hxx>
125 #include <svl/itemiter.hxx>
126 #include <svl/whiter.hxx>
128 #include <comphelper/indexedpropertyvalues.hxx>
129 #include <comphelper/processfactory.hxx>
130 #include <basic/basmgr.hxx>
132 #include "ww8toolbar.hxx"
133 #include <o3tl/unit_conversion.hxx>
134 #include <o3tl/safeint.hxx>
135 #include <osl/file.hxx>
137 #include <breakit.hxx>
139 #include <sfx2/docfile.hxx>
141 #include "WW8Sttbf.hxx"
142 #include "WW8FibData.hxx"
143 #include <unordered_set>
146 #include <com/sun/star/i18n/XBreakIterator.hpp>
147 #include <com/sun/star/i18n/ScriptType.hpp>
148 #include <unotools/pathoptions.hxx>
149 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
151 #include <com/sun/star/script/vba/XVBACompatibility.hpp>
152 #include <comphelper/sequenceashashmap.hxx>
153 #include <oox/ole/vbaproject.hxx>
154 #include <oox/ole/olestorage.hxx>
155 #include <comphelper/storagehelper.hxx>
156 #include <sfx2/DocumentMetadataAccess.hxx>
157 #include <comphelper/diagnose_ex.hxx>
158 #include <officecfg/Office/Common.hxx>
159 #include <unotxdoc.hxx>
161 using namespace ::com::sun::star
;
162 using namespace sw::util
;
163 using namespace sw::types
;
164 using namespace nsHdFtFlags
;
166 static SwMacroInfo
* GetMacroInfo( SdrObject
* pObj
)
170 sal_uInt16 nCount
= pObj
->GetUserDataCount();
171 for( sal_uInt16 i
= 0; i
< nCount
; i
++ )
173 SdrObjUserData
* pData
= pObj
->GetUserData( i
);
174 if( pData
&& pData
->GetInventor() == SdrInventor::ScOrSwDraw
175 && pData
->GetId() == SW_UD_IMAPDATA
)
177 return dynamic_cast<SwMacroInfo
*>(pData
);
180 SwMacroInfo
* pData
= new SwMacroInfo
;
181 pObj
->AppendUserData(std::unique_ptr
<SdrObjUserData
>(pData
));
188 static void lclGetAbsPath(OUString
& rPath
, sal_uInt16 nLevel
, SwDocShell
const * pDocShell
)
190 OUStringBuffer aTmpStr
;
193 aTmpStr
.append("../");
196 if (!aTmpStr
.isEmpty())
197 aTmpStr
.append(rPath
);
201 if (!aTmpStr
.isEmpty())
203 bool bWasAbs
= false;
204 rPath
= pDocShell
->GetMedium()->GetURLObject().smartRel2Abs( aTmpStr
.makeStringAndClear(), bWasAbs
).GetMainURL( INetURLObject::DecodeMechanism::NONE
);
205 // full path as stored in SvxURLField must be encoded
211 void lclIgnoreUString32(SvStream
& rStrm
)
213 sal_uInt32
nChars(0);
214 rStrm
.ReadUInt32(nChars
);
216 rStrm
.SeekRel(nChars
);
220 // returns true if an embedded null was found
221 static bool clipToFirstNull(OUString
& rStr
)
223 sal_Int32 nEmbeddedNullIdx
= rStr
.indexOf(0);
224 if (nEmbeddedNullIdx
!= -1)
225 rStr
= rStr
.copy(0, nEmbeddedNullIdx
);
226 return nEmbeddedNullIdx
!= -1;
229 void SwWW8ImplReader::ReadEmbeddedData(SvStream
& rStrm
, SwDocShell
const * pDocShell
, struct HyperLinksTable
& hlStr
)
232 // const sal_uInt16 WW8_ID_HLINK = 0x01B8;
233 constexpr sal_uInt32 WW8_HLINK_BODY
= 0x00000001; /// Contains file link or URL.
234 constexpr sal_uInt32 WW8_HLINK_ABS
= 0x00000002; /// Absolute path.
235 constexpr sal_uInt32 WW8_HLINK_DESCR
= 0x00000014; /// Description.
236 constexpr sal_uInt32 WW8_HLINK_MARK
= 0x00000008; /// Text mark.
237 constexpr sal_uInt32 WW8_HLINK_FRAME
= 0x00000080; /// Target frame.
238 constexpr sal_uInt32 WW8_HLINK_UNC
= 0x00000100; /// UNC path.
240 //sal_uInt8 maGuidStdLink[ 16 ] ={
241 // 0xD0, 0xC9, 0xEA, 0x79, 0xF9, 0xBA, 0xCE, 0x11, 0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B };
243 sal_uInt8
const aGuidUrlMoniker
[ 16 ] = {
244 0xE0, 0xC9, 0xEA, 0x79, 0xF9, 0xBA, 0xCE, 0x11, 0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B };
246 sal_uInt8
const aGuidFileMoniker
[ 16 ] = {
247 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 };
250 sal_uInt32
nFlags(0);
252 rStrm
.ReadBytes(aGuid
, 16);
254 rStrm
.ReadUInt32( nFlags
);
256 std::unique_ptr
< OUString
> xLongName
; // link / file name
257 std::unique_ptr
< OUString
> xShortName
; // 8.3-representation of file name
258 std::unique_ptr
< OUString
> xTextMark
; // text mark
260 // description (ignore)
261 if( ::get_flag( nFlags
, WW8_HLINK_DESCR
) )
262 lclIgnoreUString32( rStrm
);
265 if( ::get_flag( nFlags
, WW8_HLINK_FRAME
) )
267 hlStr
.tarFrame
= read_uInt32_lenPrefixed_uInt16s_ToOUString(rStrm
);
271 if( ::get_flag( nFlags
, WW8_HLINK_UNC
) )
273 // MS-OSHARED: An unsigned integer that specifies the number of Unicode characters in the
274 // string field, including the null-terminating character.
275 sal_uInt32
nStrLen(0);
276 rStrm
.ReadUInt32(nStrLen
);
279 xLongName
.reset(new OUString(read_uInt16s_ToOUString(rStrm
, nStrLen
- 1)));
280 rStrm
.SeekRel(sizeof(sal_Unicode
)); // skip null-byte at end
281 lclGetAbsPath( *xLongName
, 0 , pDocShell
);
285 else if( ::get_flag( nFlags
, WW8_HLINK_BODY
) )
287 rStrm
.ReadBytes(aGuid
, 16);
289 if( memcmp(aGuid
, aGuidFileMoniker
, 16) == 0 )
291 sal_uInt16 nLevel
= 0; // counter for level to climb down in path
292 rStrm
.ReadUInt16( nLevel
);
293 // MS-OSHARED: An unsigned integer that specifies the number of
294 // ANSI characters in ansiPath, including the terminating NULL character
295 sal_uInt32 nUnits
= 0;
296 rStrm
.ReadUInt32(nUnits
);
298 xShortName
.reset(new OUString
);
301 OString
sStr(read_uInt8s_ToOString(rStrm
, nUnits
- 1));
302 rStrm
.SeekRel(sizeof(sal_uInt8
)); // skip null-byte at end
303 xShortName
.reset(new OUString(sStr
.getStr(), sStr
.getLength(), GetCharSetFromLanguage()));
307 sal_uInt32
nStrLen(0);
308 rStrm
.ReadUInt32( nStrLen
);
312 rStrm
.ReadUInt32( nStrLen
);
315 // MS-OSHARED: This array MUST not include a terminating NULL character.
316 xLongName
.reset(new OUString(read_uInt16s_ToOUString(rStrm
, nStrLen
)));
317 lclGetAbsPath( *xLongName
, nLevel
, pDocShell
);
320 lclGetAbsPath( *xShortName
, nLevel
, pDocShell
);
322 else if( memcmp(aGuid
, aGuidUrlMoniker
, 16) == 0 )
324 // MS-OSHARED: An unsigned integer that specifies the size of this
325 // structure in bytes, excluding the size of the length field. The
326 // value of this field MUST be ... the byte size of the url
327 // field (including the terminating NULL character)
328 sal_uInt32
nStrLen(0);
329 rStrm
.ReadUInt32( nStrLen
);
332 xLongName
.reset(new OUString
);
335 xLongName
.reset(new OUString(read_uInt16s_ToOUString(rStrm
, nStrLen
- 1)));
336 rStrm
.SeekRel(sizeof(sal_Unicode
)); // skip null-byte at end
338 if( !::get_flag( nFlags
, WW8_HLINK_ABS
) )
339 lclGetAbsPath( *xLongName
, 0 ,pDocShell
);
343 SAL_INFO("sw.ww8", "WW8Hyperlink::ReadEmbeddedData - unknown content GUID");
348 if( ::get_flag( nFlags
, WW8_HLINK_MARK
) )
350 xTextMark
.reset(new OUString(read_uInt32_lenPrefixed_uInt16s_ToOUString(rStrm
)));
351 if (clipToFirstNull(*xTextMark
))
352 SAL_WARN("sw.ww8", "HLINK_MARK with embedded null, truncating to: " << *xTextMark
);
355 if (!xLongName
&& xShortName
)
356 xLongName
.reset(new OUString(*xShortName
));
357 else if (!xLongName
&& xTextMark
)
358 xLongName
.reset( new OUString
);
362 if (clipToFirstNull(*xLongName
))
363 SAL_WARN("sw.ww8", "HLINK with embedded null, truncating to: " << *xLongName
);
366 if (xLongName
->isEmpty())
367 *xTextMark
= xTextMark
->replace('!', '.');
368 *xLongName
+= "#" + *xTextMark
;
370 hlStr
.hLinkAddr
= *xLongName
;
376 class BasicProjImportHelper
378 SwDocShell
& mrDocShell
;
379 uno::Reference
< uno::XComponentContext
> mxCtx
;
381 explicit BasicProjImportHelper( SwDocShell
& rShell
) : mrDocShell( rShell
),
382 mxCtx(comphelper::getProcessComponentContext())
385 bool import( const uno::Reference
< io::XInputStream
>& rxIn
);
386 OUString
getProjectName() const;
391 bool BasicProjImportHelper::import( const uno::Reference
< io::XInputStream
>& rxIn
)
396 oox::ole::OleStorage
root( mxCtx
, rxIn
, false );
397 oox::StorageRef vbaStg
= root
.openSubStorage( u
"Macros"_ustr
, false );
400 oox::ole::VbaProject
aVbaPrj( mxCtx
, mrDocShell
.GetModel(), u
"Writer" );
401 bRet
= aVbaPrj
.importVbaProject( *vbaStg
);
404 catch( const uno::Exception
& )
411 OUString
BasicProjImportHelper::getProjectName() const
413 OUString
sProjName( u
"Standard"_ustr
);
414 uno::Reference
< beans::XPropertySet
> xProps( mrDocShell
.GetModel(), uno::UNO_QUERY
);
419 uno::Reference
< script::vba::XVBACompatibility
> xVBA( xProps
->getPropertyValue( u
"BasicLibraries"_ustr
), uno::UNO_QUERY
);
422 sProjName
= xVBA
->getProjectName();
425 catch( const uno::Exception
& )
433 class Sttb
: public TBBase
439 SBBItem() : cchData(0){}
441 sal_uInt16 m_fExtend
;
443 sal_uInt16 m_cbExtra
;
445 std::vector
< SBBItem
> m_dataItems
;
447 Sttb(Sttb
const&) = delete;
448 Sttb
& operator=(Sttb
const&) = delete;
453 bool Read(SvStream
&rS
) override
;
454 OUString
getStringAtIndex( sal_uInt32
);
466 bool Sttb::Read( SvStream
& rS
)
468 SAL_INFO("sw.ww8", "stream pos " << rS
.Tell());
470 rS
.ReadUInt16( m_fExtend
).ReadUInt16( m_cData
).ReadUInt16( m_cbExtra
);
473 //if they are all going to be empty strings, how many could there be
474 const size_t nMaxPossibleRecords
= rS
.remainingSize() / sizeof(sal_uInt16
);
475 if (m_cData
> nMaxPossibleRecords
)
477 for ( sal_Int32 index
= 0; index
< m_cData
; ++index
)
480 rS
.ReadUInt16( aItem
.cchData
);
481 aItem
.data
= read_uInt16s_ToOUString(rS
, aItem
.cchData
);
482 m_dataItems
.push_back( aItem
);
489 Sttb::getStringAtIndex( sal_uInt32 index
)
492 if ( index
< m_dataItems
.size() )
493 aRet
= m_dataItems
[ index
].data
;
498 SwMSDffManager::SwMSDffManager( SwWW8ImplReader
& rRdr
, bool bSkipImages
)
499 : SvxMSDffManager(*rRdr
.m_pTableStream
, rRdr
.GetBaseURL(), rRdr
.m_xWwFib
->m_fcDggInfo
,
500 rRdr
.m_pDataStream
, nullptr, 0, COL_WHITE
, rRdr
.m_pStrm
, bSkipImages
),
501 m_rReader(rRdr
), m_pFallbackStream(nullptr)
503 SetSvxMSDffSettings( GetSvxMSDffSettings() );
504 nSvxMSDffOLEConvFlags
= SwMSDffManager::GetFilterFlags();
507 sal_uInt32
SwMSDffManager::GetFilterFlags()
509 sal_uInt32
nFlags(0);
510 if (officecfg::Office::Common::Filter::Microsoft::Import::MathTypeToMath::get())
511 nFlags
|= OLE_MATHTYPE_2_STARMATH
;
512 if (officecfg::Office::Common::Filter::Microsoft::Import::ExcelToCalc::get())
513 nFlags
|= OLE_EXCEL_2_STARCALC
;
514 if (officecfg::Office::Common::Filter::Microsoft::Import::PowerPointToImpress::get())
515 nFlags
|= OLE_POWERPOINT_2_STARIMPRESS
;
516 if (officecfg::Office::Common::Filter::Microsoft::Import::WinWordToWriter::get())
517 nFlags
|= OLE_WINWORD_2_STARWRITER
;
522 * I would like to override the default OLE importing to add a test
523 * and conversion of OCX controls from their native OLE type into our
524 * native nonOLE Form Control Objects.
526 // #i32596# - consider new parameter <_nCalledByGroup>
527 rtl::Reference
<SdrObject
> SwMSDffManager::ImportOLE( sal_uInt32 nOLEId
,
529 const tools::Rectangle
& rBoundRect
,
530 const tools::Rectangle
& rVisArea
,
531 const int _nCalledByGroup
) const
533 // #i32596# - no import of OLE object, if it's inside a group.
534 // NOTE: This can be undone, if grouping of Writer fly frames is possible or
535 // if drawing OLE objects are allowed in Writer.
536 if ( _nCalledByGroup
> 0 )
541 rtl::Reference
<SdrObject
> pRet
;
542 OUString sStorageName
;
543 rtl::Reference
<SotStorage
> xSrcStg
;
544 uno::Reference
< embed::XStorage
> xDstStg
;
545 if( GetOLEStorageName( nOLEId
, sStorageName
, xSrcStg
, xDstStg
))
547 rtl::Reference
<SotStorage
> xSrc
= xSrcStg
->OpenSotStorage(sStorageName
);
548 OSL_ENSURE(m_rReader
.m_xFormImpl
, "No Form Implementation!");
549 css::uno::Reference
< css::drawing::XShape
> xShape
;
550 if ( (!(m_rReader
.m_bIsHeader
|| m_rReader
.m_bIsFooter
)) &&
551 m_rReader
.m_xFormImpl
->ReadOCXStream(xSrc
,&xShape
,true))
553 pRet
= SdrObject::getSdrObjectFromXShape(xShape
);
557 ErrCode nError
= ERRCODE_NONE
;
558 pRet
= CreateSdrOLEFromStorage(
568 nSvxMSDffOLEConvFlags
,
569 css::embed::Aspects::MSOLE_CONTENT
,
570 m_rReader
.GetBaseURL());
576 void SwMSDffManager::DisableFallbackStream()
578 OSL_ENSURE(!m_pFallbackStream
,
579 "if you're recursive, you're broken");
580 m_pFallbackStream
= pStData2
;
581 m_aOldEscherBlipCache
= aEscherBlipCache
;
582 aEscherBlipCache
.clear();
586 void SwMSDffManager::EnableFallbackStream()
588 pStData2
= m_pFallbackStream
;
589 aEscherBlipCache
= m_aOldEscherBlipCache
;
590 m_aOldEscherBlipCache
.clear();
591 m_pFallbackStream
= nullptr;
594 sal_uInt16
SwWW8ImplReader::GetToggleAttrFlags() const
596 return m_xCtrlStck
? m_xCtrlStck
->GetToggleAttrFlags() : 0;
599 sal_uInt16
SwWW8ImplReader::GetToggleBiDiAttrFlags() const
601 return m_xCtrlStck
? m_xCtrlStck
->GetToggleBiDiAttrFlags() : 0;
604 void SwWW8ImplReader::SetToggleAttrFlags(sal_uInt16 nFlags
)
607 m_xCtrlStck
->SetToggleAttrFlags(nFlags
);
610 void SwWW8ImplReader::SetToggleBiDiAttrFlags(sal_uInt16 nFlags
)
613 m_xCtrlStck
->SetToggleBiDiAttrFlags(nFlags
);
616 rtl::Reference
<SdrObject
> SwMSDffManager::ProcessObj(SvStream
& rSt
,
617 DffObjData
& rObjData
,
618 SvxMSDffClientData
& rData
,
619 tools::Rectangle
& rTextRect
,
623 rtl::Reference
<SdrObject
> pObj
= pObj1
;
624 if( !rTextRect
.IsEmpty() )
626 SvxMSDffImportData
& rImportData
= static_cast<SvxMSDffImportData
&>(rData
);
627 std::unique_ptr
<SvxMSDffImportRec
> pImpRec(new SvxMSDffImportRec
);
629 // fill Import Record with data
630 pImpRec
->nShapeId
= rObjData
.nShapeId
;
631 pImpRec
->eShapeType
= rObjData
.eShapeType
;
633 rObjData
.bClientAnchor
= maShapeRecords
.SeekToContent( rSt
,
634 DFF_msofbtClientAnchor
,
635 SEEK_FROM_CURRENT_AND_RESTART
);
636 if( rObjData
.bClientAnchor
)
637 ProcessClientAnchor( rSt
,
638 maShapeRecords
.Current()->nRecLen
,
639 pImpRec
->pClientAnchorBuffer
, pImpRec
->nClientAnchorLen
);
641 rObjData
.bClientData
= maShapeRecords
.SeekToContent( rSt
,
642 DFF_msofbtClientData
,
643 SEEK_FROM_CURRENT_AND_RESTART
);
644 if( rObjData
.bClientData
)
645 ProcessClientData( rSt
,
646 maShapeRecords
.Current()->nRecLen
,
647 pImpRec
->pClientDataBuffer
, pImpRec
->nClientDataLen
);
649 pImpRec
->nGroupShapeBooleanProperties
= 0;
651 if( maShapeRecords
.SeekToContent( rSt
,
653 SEEK_FROM_CURRENT_AND_RESTART
)
654 && maShapeRecords
.Current()->nRecLen
)
656 sal_uInt32 nBytesLeft
= maShapeRecords
.Current()->nRecLen
;
657 auto nAvailableBytes
= rSt
.remainingSize();
658 if (nBytesLeft
> nAvailableBytes
)
660 SAL_WARN("sw.ww8", "Document claimed to have shape record of " << nBytesLeft
<< " bytes, but only " << nAvailableBytes
<< " available");
661 nBytesLeft
= nAvailableBytes
;
663 while( 5 < nBytesLeft
)
666 rSt
.ReadUInt16(nPID
);
667 sal_uInt32
nUDData(0);
668 rSt
.ReadUInt32(nUDData
);
673 case 0x038F: pImpRec
->nXAlign
= nUDData
; break;
675 pImpRec
->nXRelTo
= nUDData
;
677 case 0x0391: pImpRec
->nYAlign
= nUDData
; break;
679 pImpRec
->nYRelTo
= nUDData
;
681 case 0x03BF: pImpRec
->nGroupShapeBooleanProperties
= nUDData
; break;
683 // This seems to correspond to o:hrpct from .docx (even including
684 // the difference that it's in 0.1% even though the .docx spec
686 pImpRec
->relativeHorizontalWidth
= nUDData
;
689 // And this is really just a guess, but a mere presence of this
690 // flag makes a horizontal rule be as wide as the page (unless
691 // overridden by something), so it probably matches o:hr from .docx.
692 pImpRec
->isHorizontalRule
= true;
699 // Text Frame also Title or Outline
700 sal_uInt32 nTextId
= GetPropertyValue( DFF_Prop_lTxid
, 0 );
703 SfxItemSet
aSet( pSdrModel
->GetItemPool() );
705 // Originally anything that as a mso_sptTextBox was created as a
706 // textbox, this was changed to be created as a simple
707 // rect to keep impress happy. For the rest of us we'd like to turn
708 // it back into a textbox again.
709 bool bIsSimpleDrawingTextBox
= (pImpRec
->eShapeType
== mso_sptTextBox
);
710 if (!bIsSimpleDrawingTextBox
)
713 // a) it's a simple text object or
714 // b) it's a rectangle with text and square wrapping.
715 bIsSimpleDrawingTextBox
=
717 (pImpRec
->eShapeType
== mso_sptTextSimple
) ||
719 (pImpRec
->eShapeType
== mso_sptRectangle
)
720 && ShapeHasText(pImpRec
->nShapeId
, rObjData
.rSpHd
.GetRecBegFilePos() )
725 // Distance of Textbox to its surrounding Autoshape
726 sal_Int32 nTextLeft
= GetPropertyValue( DFF_Prop_dxTextLeft
, 91440);
727 sal_Int32 nTextRight
= GetPropertyValue( DFF_Prop_dxTextRight
, 91440 );
728 sal_Int32 nTextTop
= GetPropertyValue( DFF_Prop_dyTextTop
, 45720 );
729 sal_Int32 nTextBottom
= GetPropertyValue( DFF_Prop_dyTextBottom
, 45720 );
731 ScaleEmu( nTextLeft
);
732 ScaleEmu( nTextRight
);
733 ScaleEmu( nTextTop
);
734 ScaleEmu( nTextBottom
);
736 Degree100 nTextRotationAngle
;
737 bool bVerticalText
= false;
738 if ( IsProperty( DFF_Prop_txflTextFlow
) )
740 MSO_TextFlow eTextFlow
= static_cast<MSO_TextFlow
>(GetPropertyValue(
741 DFF_Prop_txflTextFlow
, 0) & 0xFFFF);
745 nTextRotationAngle
= 9000_deg100
;
749 nTextRotationAngle
= 27000_deg100
;
752 bVerticalText
= true;
755 bVerticalText
= true;
756 nTextRotationAngle
= 9000_deg100
;
764 if (nTextRotationAngle
)
766 if (nTextRotationAngle
== 9000_deg100
)
768 tools::Long nWidth
= rTextRect
.GetWidth();
769 rTextRect
.SetRight( rTextRect
.Left() + rTextRect
.GetHeight() );
770 rTextRect
.SetBottom( rTextRect
.Top() + nWidth
);
772 sal_Int32 nOldTextLeft
= nTextLeft
;
773 sal_Int32 nOldTextRight
= nTextRight
;
774 sal_Int32 nOldTextTop
= nTextTop
;
775 sal_Int32 nOldTextBottom
= nTextBottom
;
777 nTextLeft
= nOldTextBottom
;
778 nTextRight
= nOldTextTop
;
779 nTextTop
= nOldTextLeft
;
780 nTextBottom
= nOldTextRight
;
782 else if (nTextRotationAngle
== 27000_deg100
)
784 tools::Long nWidth
= rTextRect
.GetWidth();
785 rTextRect
.SetRight( rTextRect
.Left() + rTextRect
.GetHeight() );
786 rTextRect
.SetBottom( rTextRect
.Top() + nWidth
);
788 sal_Int32 nOldTextLeft
= nTextLeft
;
789 sal_Int32 nOldTextRight
= nTextRight
;
790 sal_Int32 nOldTextTop
= nTextTop
;
791 sal_Int32 nOldTextBottom
= nTextBottom
;
793 nTextLeft
= nOldTextTop
;
794 nTextRight
= nOldTextBottom
;
795 nTextTop
= nOldTextRight
;
796 nTextBottom
= nOldTextLeft
;
800 if (bIsSimpleDrawingTextBox
)
802 pObj
= new SdrRectObj(
808 // The vertical paragraph justification are contained within the
809 // BoundRect so calculate it here
810 tools::Rectangle
aNewRect(rTextRect
);
811 aNewRect
.AdjustBottom( -(nTextTop
+ nTextBottom
) );
812 aNewRect
.AdjustRight( -(nTextLeft
+ nTextRight
) );
814 // Only if it's a simple Textbox, Writer can replace the Object
815 // with a Frame, else
816 if( bIsSimpleDrawingTextBox
)
818 std::shared_ptr
<SvxMSDffShapeInfo
> const xTmpRec
=
819 std::make_shared
<SvxMSDffShapeInfo
>(0, pImpRec
->nShapeId
);
821 SvxMSDffShapeInfos_ById::const_iterator
const it
=
822 GetShapeInfos()->find(xTmpRec
);
823 if (it
!= GetShapeInfos()->end())
825 SvxMSDffShapeInfo
& rInfo
= **it
;
826 pImpRec
->bReplaceByFly
= rInfo
.bReplaceByFly
;
829 ApplyAttributes(rSt
, aSet
, rObjData
);
832 if (GetPropertyValue(DFF_Prop_FitTextToShape
, 0) & 2)
834 aSet
.Put( makeSdrTextAutoGrowHeightItem( true ) );
835 aSet
.Put( makeSdrTextMinFrameHeightItem(
836 aNewRect
.Bottom() - aNewRect
.Top() ) );
837 aSet
.Put( makeSdrTextMinFrameWidthItem(
838 aNewRect
.Right() - aNewRect
.Left() ) );
842 aSet
.Put( makeSdrTextAutoGrowHeightItem( false ) );
843 aSet
.Put( makeSdrTextAutoGrowWidthItem( false ) );
846 switch ( static_cast<MSO_WrapMode
>(GetPropertyValue( DFF_Prop_WrapText
, mso_wrapSquare
)) )
849 aSet
.Put( makeSdrTextAutoGrowWidthItem( true ) );
850 pImpRec
->bAutoWidth
= true;
852 case mso_wrapByPoints
:
853 aSet
.Put( makeSdrTextContourFrameItem( true ) );
859 // Set distances on Textbox's margins
860 aSet
.Put( makeSdrTextLeftDistItem( nTextLeft
) );
861 aSet
.Put( makeSdrTextRightDistItem( nTextRight
) );
862 aSet
.Put( makeSdrTextUpperDistItem( nTextTop
) );
863 aSet
.Put( makeSdrTextLowerDistItem( nTextBottom
) );
864 pImpRec
->nDxTextLeft
= nTextLeft
;
865 pImpRec
->nDyTextTop
= nTextTop
;
866 pImpRec
->nDxTextRight
= nTextRight
;
867 pImpRec
->nDyTextBottom
= nTextBottom
;
869 // Taking the correct default (which is mso_anchorTop)
870 sal_uInt32 eTextAnchor
=
871 GetPropertyValue( DFF_Prop_anchorText
, mso_anchorTop
);
873 SdrTextVertAdjust eTVA
= bVerticalText
874 ? SDRTEXTVERTADJUST_BLOCK
875 : SDRTEXTVERTADJUST_CENTER
;
876 SdrTextHorzAdjust eTHA
= bVerticalText
877 ? SDRTEXTHORZADJUST_CENTER
878 : SDRTEXTHORZADJUST_BLOCK
;
880 switch( eTextAnchor
)
883 case mso_anchorTopCentered
:
886 eTHA
= SDRTEXTHORZADJUST_RIGHT
;
888 eTVA
= SDRTEXTVERTADJUST_TOP
;
891 case mso_anchorMiddle
:
893 case mso_anchorMiddleCentered
:
895 case mso_anchorBottom
:
896 case mso_anchorBottomCentered
:
899 eTHA
= SDRTEXTHORZADJUST_LEFT
;
901 eTVA
= SDRTEXTVERTADJUST_BOTTOM
;
908 aSet
.Put( SdrTextVertAdjustItem( eTVA
) );
909 aSet
.Put( SdrTextHorzAdjustItem( eTHA
) );
913 pObj
->SetMergedItemSet(aSet
);
917 SdrTextObj
*pTextObj
= DynCastSdrTextObj(pObj
.get());
919 pTextObj
->SetVerticalWriting(true);
922 if ( bIsSimpleDrawingTextBox
)
924 if ( nTextRotationAngle
)
926 tools::Long nMinWH
= rTextRect
.GetWidth() < rTextRect
.GetHeight() ?
927 rTextRect
.GetWidth() : rTextRect
.GetHeight();
929 Point
aPivot(rTextRect
.TopLeft());
930 aPivot
.AdjustX(nMinWH
);
931 aPivot
.AdjustY(nMinWH
);
932 pObj
->NbcRotate(aPivot
, nTextRotationAngle
);
936 if ( ( ( rObjData
.nSpFlags
& ShapeFlag::FlipV
) || mnFix16Angle
|| nTextRotationAngle
) && dynamic_cast< SdrObjCustomShape
* >( pObj
.get() ) )
938 SdrObjCustomShape
* pCustomShape
= dynamic_cast< SdrObjCustomShape
* >( pObj
.get() );
941 double fExtraTextRotation
= 0.0;
942 if ( mnFix16Angle
&& !( GetPropertyValue( DFF_Prop_FitTextToShape
, 0 ) & 4 ) )
943 { // text is already rotated, we have to take back the object rotation if DFF_Prop_RotateText is false
944 fExtraTextRotation
= -mnFix16Angle
.get();
946 if ( rObjData
.nSpFlags
& ShapeFlag::FlipV
) // sj: in ppt the text is flipped, whereas in word the text
947 { // remains unchanged, so we have to take back the flipping here
948 fExtraTextRotation
+= 18000.0; // because our core will flip text if the shape is flipped.
950 fExtraTextRotation
+= nTextRotationAngle
.get();
951 if ( !::basegfx::fTools::equalZero( fExtraTextRotation
) )
953 fExtraTextRotation
/= 100.0;
954 SdrCustomShapeGeometryItem
aGeometryItem( pCustomShape
->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY
) );
955 css::beans::PropertyValue aPropVal
;
956 aPropVal
.Name
= "TextRotateAngle";
957 aPropVal
.Value
<<= fExtraTextRotation
;
958 aGeometryItem
.SetPropertyValue( aPropVal
);
959 pCustomShape
->SetMergedItem( aGeometryItem
);
963 else if ( mnFix16Angle
)
965 // rotate text with shape ?
966 pObj
->NbcRotate( rObjData
.aBoundRect
.Center(), mnFix16Angle
);
972 // simple rectangular objects are ignored by ImportObj() :-(
973 // this is OK for Draw but not for Calc and Writer
974 // cause here these objects have a default border
975 pObj
= new SdrRectObj(
979 SfxItemSet
aSet( pSdrModel
->GetItemPool() );
980 ApplyAttributes( rSt
, aSet
, rObjData
);
982 SfxItemState eState
= aSet
.GetItemState( XATTR_FILLCOLOR
, false );
983 if( SfxItemState::DEFAULT
== eState
)
984 aSet
.Put( XFillColorItem( OUString(), mnDefaultColor
) );
985 pObj
->SetMergedItemSet(aSet
);
988 // Means that fBehindDocument is set
989 if (GetPropertyValue(DFF_Prop_fPrint
, 0) & 0x20)
990 pImpRec
->bDrawHell
= true;
992 pImpRec
->bDrawHell
= false;
993 if (GetPropertyValue(DFF_Prop_fPrint
, 0) & 0x02)
994 pImpRec
->bHidden
= true;
995 pImpRec
->nNextShapeId
= GetPropertyValue( DFF_Prop_hspNext
, 0 );
999 pImpRec
->aTextId
.nTxBxS
= o3tl::narrowing
<sal_uInt16
>( nTextId
>> 16 );
1000 pImpRec
->aTextId
.nSequence
= o3tl::narrowing
<sal_uInt16
>(nTextId
);
1003 pImpRec
->nDxWrapDistLeft
= o3tl::convert(GetPropertyValue(DFF_Prop_dxWrapDistLeft
, 114935),
1004 o3tl::Length::emu
, o3tl::Length::twip
);
1005 pImpRec
->nDyWrapDistTop
= o3tl::convert(GetPropertyValue(DFF_Prop_dyWrapDistTop
, 0),
1006 o3tl::Length::emu
, o3tl::Length::twip
);
1007 pImpRec
->nDxWrapDistRight
1008 = o3tl::convert(GetPropertyValue(DFF_Prop_dxWrapDistRight
, 114935), o3tl::Length::emu
,
1009 o3tl::Length::twip
);
1010 pImpRec
->nDyWrapDistBottom
= o3tl::convert(GetPropertyValue(DFF_Prop_dyWrapDistBottom
, 0),
1011 o3tl::Length::emu
, o3tl::Length::twip
);
1012 // 16.16 fraction times total image width or height, as appropriate.
1014 if (SeekToContent(DFF_Prop_pWrapPolygonVertices
, rSt
))
1016 pImpRec
->pWrapPolygon
.reset();
1018 sal_uInt16
nNumElemVert(0), nNumElemMemVert(0), nElemSizeVert(0);
1019 rSt
.ReadUInt16( nNumElemVert
).ReadUInt16( nNumElemMemVert
).ReadUInt16( nElemSizeVert
);
1021 if (nNumElemVert
&& (nElemSizeVert
== 8 || nElemSizeVert
== 4))
1023 //check if there is enough data in the file to make the
1025 // coverity[tainted_data : FALSE] - nElemSizeVert is either 8 or 4 so it has been sanitized
1026 bOk
= rSt
.remainingSize() / nElemSizeVert
>= nNumElemVert
;
1030 pImpRec
->pWrapPolygon
= tools::Polygon(nNumElemVert
);
1031 for (sal_uInt16 i
= 0; i
< nNumElemVert
; ++i
)
1033 sal_Int32
nX(0), nY(0);
1034 if (nElemSizeVert
== 8)
1035 rSt
.ReadInt32( nX
).ReadInt32( nY
);
1038 sal_Int16
nSmallX(0), nSmallY(0);
1039 rSt
.ReadInt16( nSmallX
).ReadInt16( nSmallY
);
1043 (*(pImpRec
->pWrapPolygon
))[i
].setX( nX
);
1044 (*(pImpRec
->pWrapPolygon
))[i
].setY( nY
);
1049 pImpRec
->nCropFromTop
= GetPropertyValue(
1050 DFF_Prop_cropFromTop
, 0 );
1051 pImpRec
->nCropFromBottom
= GetPropertyValue(
1052 DFF_Prop_cropFromBottom
, 0 );
1053 pImpRec
->nCropFromLeft
= GetPropertyValue(
1054 DFF_Prop_cropFromLeft
, 0 );
1055 pImpRec
->nCropFromRight
= GetPropertyValue(
1056 DFF_Prop_cropFromRight
, 0 );
1058 sal_uInt32 nLineFlags
= GetPropertyValue( DFF_Prop_fNoLineDrawDash
, 0 );
1060 if ( !IsHardAttribute( DFF_Prop_fLine
) &&
1061 pImpRec
->eShapeType
== mso_sptPictureFrame
)
1063 nLineFlags
&= ~0x08;
1066 pImpRec
->eLineStyle
= (nLineFlags
& 8)
1067 ? static_cast<MSO_LineStyle
>(GetPropertyValue(
1070 : MSO_LineStyle(USHRT_MAX
);
1071 pImpRec
->eLineDashing
= static_cast<MSO_LineDashing
>(GetPropertyValue(
1072 DFF_Prop_lineDashing
, mso_lineSolid
));
1074 pImpRec
->nFlags
= rObjData
.nSpFlags
;
1076 if( pImpRec
->nShapeId
)
1078 auto nShapeId
= pImpRec
->nShapeId
;
1079 auto nShapeOrder
= (static_cast<sal_uLong
>(pImpRec
->aTextId
.nTxBxS
) << 16)
1080 + pImpRec
->aTextId
.nSequence
;
1081 // Complement Import Record List
1082 pImpRec
->pObj
= pObj
;
1083 rImportData
.insert(std::move(pImpRec
));
1085 // Complement entry in Z Order List with a pointer to this Object
1086 // Only store objects which are not deep inside the tree
1087 if( ( rObjData
.nCalledByGroup
== 0 )
1089 ( (rObjData
.nSpFlags
& ShapeFlag::Group
)
1090 && (rObjData
.nCalledByGroup
< 2) )
1093 StoreShapeOrder(nShapeId
, nShapeOrder
, pObj
.get());
1100 sal_uInt32 nBufferSize
= GetPropertyValue( DFF_Prop_pihlShape
, 0 );
1101 if( (0 < nBufferSize
) && (nBufferSize
<= 0xFFFF) && SeekToContent( DFF_Prop_pihlShape
, rSt
) )
1103 SvMemoryStream aMemStream
;
1104 struct HyperLinksTable hlStr
;
1105 aMemStream
.WriteUInt16( 0 ).WriteUInt16( nBufferSize
);
1107 // copy from DFF stream to memory stream
1108 std::vector
< sal_uInt8
> aBuffer( nBufferSize
);
1109 if (rSt
.ReadBytes(aBuffer
.data(), nBufferSize
) == nBufferSize
)
1111 aMemStream
.WriteBytes(aBuffer
.data(), nBufferSize
);
1112 sal_uInt64 nStreamSize
= aMemStream
.TellEnd();
1113 aMemStream
.Seek( STREAM_SEEK_TO_BEGIN
);
1114 bool bRet
= 4 <= nStreamSize
;
1115 sal_uInt16 nRawRecId
,nRawRecSize
;
1117 aMemStream
.ReadUInt16( nRawRecId
).ReadUInt16( nRawRecSize
);
1118 SwDocShell
* pDocShell
= m_rReader
.m_pDocShell
;
1121 m_rReader
.ReadEmbeddedData(aMemStream
, pDocShell
, hlStr
);
1125 if (pObj
&& !hlStr
.hLinkAddr
.isEmpty())
1127 SwMacroInfo
* pInfo
= GetMacroInfo( pObj
.get() );
1130 pInfo
->SetShapeId( rObjData
.nShapeId
);
1131 pInfo
->SetHlink( hlStr
.hLinkAddr
);
1132 if (!hlStr
.tarFrame
.isEmpty())
1133 pInfo
->SetTarFrame( hlStr
.tarFrame
);
1134 OUString aNameStr
= GetPropertyString( DFF_Prop_wzName
, rSt
);
1135 if (!aNameStr
.isEmpty())
1136 pInfo
->SetName( aNameStr
);
1145 * Special FastSave - Attributes
1147 void SwWW8ImplReader::Read_StyleCode( sal_uInt16
, const sal_uInt8
* pData
, short nLen
)
1151 m_bCpxStyle
= false;
1154 sal_uInt16 nColl
= 0;
1155 if (m_xWwFib
->GetFIBVersion() <= ww::eWW2
)
1158 nColl
= SVBT16ToUInt16(pData
);
1159 if (nColl
< m_vColl
.size())
1161 SetTextFormatCollAndListLevel( *m_pPaM
, m_vColl
[nColl
] );
1167 * Read_Majority is for Majority (103) and Majority50 (108)
1169 void SwWW8ImplReader::Read_Majority( sal_uInt16
, const sal_uInt8
* , short )
1176 void SwWW8FltControlStack::NewAttr(const SwPosition
& rPos
,
1177 const SfxPoolItem
& rAttr
)
1179 OSL_ENSURE(RES_TXTATR_FIELD
!= rAttr
.Which(), "probably don't want to put"
1180 "fields into the control stack");
1181 OSL_ENSURE(RES_TXTATR_INPUTFIELD
!= rAttr
.Which(), "probably don't want to put"
1182 "input fields into the control stack");
1183 OSL_ENSURE(RES_TXTATR_ANNOTATION
!= rAttr
.Which(), "probably don't want to put"
1184 "annotations into the control stack");
1185 OSL_ENSURE(RES_FLTR_REDLINE
!= rAttr
.Which(), "probably don't want to put"
1186 "redlines into the control stack");
1187 SwFltControlStack::NewAttr(rPos
, rAttr
);
1190 SwFltStackEntry
* SwWW8FltControlStack::SetAttr(const SwPosition
& rPos
, sal_uInt16 nAttrId
,
1191 bool bTstEnd
, tools::Long nHand
, bool )
1193 SwFltStackEntry
*pRet
= nullptr;
1194 // Doing a textbox, and using the control stack only as a temporary
1195 // collection point for properties which will are not to be set into
1196 // the real document
1197 if (m_rReader
.m_xPlcxMan
&& m_rReader
.m_xPlcxMan
->GetDoingDrawTextBox())
1199 size_t nCnt
= size();
1203 SwFltStackEntry
& rEntry
= (*this)[i
];
1204 if (nAttrId
== rEntry
.m_pAttr
->Which())
1206 DeleteAndDestroy(i
);
1213 else // Normal case, set the attribute into the document
1214 pRet
= SwFltControlStack::SetAttr(rPos
, nAttrId
, bTstEnd
, nHand
);
1218 tools::Long
GetListFirstLineIndent(const SwNumFormat
&rFormat
)
1220 OSL_ENSURE( rFormat
.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION
,
1221 "<GetListFirstLineIndent> - misusage: position-and-space-mode does not equal LABEL_WIDTH_AND_POSITION" );
1223 SvxAdjust eAdj
= rFormat
.GetNumAdjust();
1224 tools::Long nReverseListIndented
;
1225 if (eAdj
== SvxAdjust::Right
)
1226 nReverseListIndented
= -rFormat
.GetCharTextDistance();
1227 else if (eAdj
== SvxAdjust::Center
)
1228 nReverseListIndented
= rFormat
.GetFirstLineOffset()/2;
1230 nReverseListIndented
= rFormat
.GetFirstLineOffset();
1231 return nReverseListIndented
;
1234 static tools::Long
lcl_GetTrueMargin(SvxFirstLineIndentItem
const& rFirstLine
,
1235 SvxTextLeftMarginItem
const& rLeftMargin
, const SwNumFormat
&rFormat
,
1236 tools::Long
&rFirstLinePos
)
1238 OSL_ENSURE( rFormat
.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION
,
1239 "<lcl_GetTrueMargin> - misusage: position-and-space-mode does not equal LABEL_WIDTH_AND_POSITION" );
1241 const tools::Long nBodyIndent
= rLeftMargin
.ResolveTextLeft({});
1242 const tools::Long nFirstLineDiff
= rFirstLine
.ResolveTextFirstLineOffset({});
1243 rFirstLinePos
= nBodyIndent
+ nFirstLineDiff
;
1245 const auto nPseudoListBodyIndent
= rFormat
.GetAbsLSpace();
1246 const tools::Long nReverseListIndented
= GetListFirstLineIndent(rFormat
);
1247 tools::Long nExtraListIndent
= nPseudoListBodyIndent
+ nReverseListIndented
;
1249 return std::max
<tools::Long
>(nExtraListIndent
, 0);
1254 void SyncIndentWithList( SvxFirstLineIndentItem
& rFirstLine
,
1255 SvxTextLeftMarginItem
& rLeftMargin
,
1256 const SwNumFormat
&rFormat
,
1257 const bool bFirstLineOfstSet
,
1258 const bool bLeftIndentSet
)
1260 if ( rFormat
.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION
)
1262 tools::Long nWantedFirstLinePos
;
1263 tools::Long nExtraListIndent
= lcl_GetTrueMargin(rFirstLine
, rLeftMargin
, rFormat
, nWantedFirstLinePos
);
1264 rLeftMargin
.SetTextLeft(SvxIndentValue::twips(nWantedFirstLinePos
- nExtraListIndent
));
1265 rFirstLine
.SetTextFirstLineOffset(SvxIndentValue::zero());
1267 else if ( rFormat
.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT
)
1269 if ( !bFirstLineOfstSet
&& bLeftIndentSet
&&
1270 rFormat
.GetFirstLineIndent() != 0 )
1272 rFirstLine
.SetTextFirstLineOffset(
1273 SvxIndentValue
{ static_cast<double>(rFormat
.GetFirstLineIndent()),
1274 rFormat
.GetFirstLineIndentUnit() });
1276 else if ( bFirstLineOfstSet
&& !bLeftIndentSet
&&
1277 rFormat
.GetIndentAt() != 0 )
1279 rLeftMargin
.SetTextLeft(SvxIndentValue::twips(rFormat
.GetIndentAt()));
1281 else if (!bFirstLineOfstSet
&& !bLeftIndentSet
)
1283 if ( rFormat
.GetFirstLineIndent() != 0 )
1285 rFirstLine
.SetTextFirstLineOffset(
1286 SvxIndentValue
{ static_cast<double>(rFormat
.GetFirstLineIndent()),
1287 rFormat
.GetFirstLineIndentUnit() });
1289 if ( rFormat
.GetIndentAt() != 0 )
1291 rLeftMargin
.SetTextLeft(SvxIndentValue::twips(rFormat
.GetIndentAt()));
1297 const SwNumFormat
* SwWW8FltControlStack::GetNumFormatFromStack(const SwPosition
&rPos
,
1298 const SwTextNode
&rTextNode
)
1300 const SwNumFormat
*pRet
= nullptr;
1301 const SfxPoolItem
*pItem
= GetStackAttr(rPos
, RES_FLTR_NUMRULE
);
1302 if (pItem
&& rTextNode
.GetNumRule())
1304 if (rTextNode
.IsCountedInList())
1306 OUString
sName(static_cast<const SfxStringItem
*>(pItem
)->GetValue());
1307 const SwNumRule
*pRule
= m_rDoc
.FindNumRulePtr(sName
);
1309 pRet
= GetNumFormatFromSwNumRuleLevel(*pRule
, rTextNode
.GetActualListLevel());
1315 void SwWW8ReferencedFltEndStack::SetAttrInDoc( const SwPosition
& rTmpPos
,
1316 SwFltStackEntry
& rEntry
)
1318 switch( rEntry
.m_pAttr
->Which() )
1320 case RES_FLTR_BOOKMARK
:
1322 // suppress insertion of bookmark, which is recognized as an internal bookmark used for table-of-content
1323 // and which is not referenced.
1324 bool bInsertBookmarkIntoDoc
= true;
1326 SwFltBookmark
* pFltBookmark
= dynamic_cast<SwFltBookmark
*>(rEntry
.m_pAttr
.get());
1327 if ( pFltBookmark
!= nullptr && pFltBookmark
->IsTOCBookmark() )
1329 const OUString
& rName
= pFltBookmark
->GetName();
1330 std::set
< OUString
, SwWW8::ltstr
>::const_iterator aResult
= m_aReferencedTOCBookmarks
.find(rName
);
1331 if ( aResult
== m_aReferencedTOCBookmarks
.end() )
1333 bInsertBookmarkIntoDoc
= false;
1336 if ( bInsertBookmarkIntoDoc
)
1338 SwFltEndStack::SetAttrInDoc( rTmpPos
, rEntry
);
1343 SwFltEndStack::SetAttrInDoc( rTmpPos
, rEntry
);
1349 void SwWW8FltControlStack::SetAttrInDoc(const SwPosition
& rTmpPos
,
1350 SwFltStackEntry
& rEntry
)
1352 switch (rEntry
.m_pAttr
->Which())
1357 case RES_MARGIN_FIRSTLINE
:
1358 case RES_MARGIN_TEXTLEFT
:
1361 Loop over the affected nodes and
1362 a) convert the word style absolute indent to indent relative
1363 to any numbering indent active on the nodes
1364 b) adjust the writer style tabstops relative to the old
1365 paragraph indent to be relative to the new paragraph indent
1367 SwPaM
aRegion(rTmpPos
);
1368 if (rEntry
.MakeRegion(aRegion
, SwFltStackEntry::RegionMode::NoCheck
))
1370 SvxFirstLineIndentItem
firstLineNew(RES_MARGIN_FIRSTLINE
);
1371 SvxTextLeftMarginItem
leftMarginNew(RES_MARGIN_TEXTLEFT
);
1372 if (rEntry
.m_pAttr
->Which() == RES_MARGIN_FIRSTLINE
)
1374 SvxFirstLineIndentItem
const firstLineEntry(*static_cast<SvxFirstLineIndentItem
*>(rEntry
.m_pAttr
.get()));
1375 firstLineNew
.SetTextFirstLineOffset(
1376 firstLineEntry
.GetTextFirstLineOffset(),
1377 firstLineEntry
.GetPropTextFirstLineOffset());
1378 firstLineNew
.SetAutoFirst(firstLineEntry
.IsAutoFirst());
1382 SvxTextLeftMarginItem
const leftMarginEntry(*static_cast<SvxTextLeftMarginItem
*>(rEntry
.m_pAttr
.get()));
1383 leftMarginNew
.SetTextLeft(leftMarginEntry
.GetTextLeft(), leftMarginEntry
.GetPropLeft());
1385 SwNodeOffset nStart
= aRegion
.Start()->GetNodeIndex();
1386 SwNodeOffset nEnd
= aRegion
.End()->GetNodeIndex();
1387 for(; nStart
<= nEnd
; ++nStart
)
1389 SwNode
* pNode
= m_rDoc
.GetNodes()[ nStart
];
1390 if (!pNode
|| !pNode
->IsTextNode())
1393 SwContentNode
* pNd
= static_cast<SwContentNode
*>(pNode
);
1394 SvxFirstLineIndentItem
firstLineOld(pNd
->GetAttr(RES_MARGIN_FIRSTLINE
));
1395 SvxTextLeftMarginItem
leftMarginOld(pNd
->GetAttr(RES_MARGIN_TEXTLEFT
));
1396 if (rEntry
.m_pAttr
->Which() == RES_MARGIN_FIRSTLINE
)
1398 leftMarginNew
.SetTextLeft(leftMarginOld
.GetTextLeft(), leftMarginOld
.GetPropLeft());
1402 firstLineNew
.SetTextFirstLineOffset(
1403 firstLineOld
.GetTextFirstLineOffset(),
1404 firstLineOld
.GetPropTextFirstLineOffset());
1405 firstLineNew
.SetAutoFirst(firstLineOld
.IsAutoFirst());
1408 SwTextNode
*pTextNode
= static_cast<SwTextNode
*>(pNode
);
1410 const SwNumFormat
* pNum
1411 = GetNumFormatFromStack(*aRegion
.GetPoint(), *pTextNode
);
1414 pNum
= GetNumFormatFromTextNode(*pTextNode
);
1420 const bool bFirstLineIndentSet
=
1421 ( m_rReader
.m_aTextNodesHavingFirstLineOfstSet
.end() !=
1422 m_rReader
.m_aTextNodesHavingFirstLineOfstSet
.find( pNode
) );
1424 const bool bLeftIndentSet
=
1425 ( m_rReader
.m_aTextNodesHavingLeftIndentSet
.end() !=
1426 m_rReader
.m_aTextNodesHavingLeftIndentSet
.find( pNode
) );
1427 SyncIndentWithList(firstLineNew
, leftMarginNew
, *pNum
,
1428 bFirstLineIndentSet
,
1432 if (firstLineNew
!= firstLineOld
)
1434 if (nStart
== aRegion
.Start()->GetNodeIndex())
1436 pNd
->SetAttr(firstLineNew
);
1439 if (leftMarginNew
!= leftMarginOld
)
1441 pNd
->SetAttr(leftMarginNew
);
1448 case RES_TXTATR_FIELD
:
1449 OSL_ENSURE(false, "What is a field doing in the control stack,"
1450 "probably should have been in the endstack");
1453 case RES_TXTATR_ANNOTATION
:
1454 OSL_ENSURE(false, "What is an annotation doing in the control stack,"
1455 "probably should have been in the endstack");
1458 case RES_TXTATR_INPUTFIELD
:
1459 OSL_ENSURE(false, "What is an input field doing in the control stack,"
1460 "probably should have been in the endstack");
1463 case RES_TXTATR_INETFMT
:
1465 SwPaM
aRegion(rTmpPos
);
1466 if (rEntry
.MakeRegion(aRegion
, SwFltStackEntry::RegionMode::NoCheck
))
1468 SwFrameFormat
*pFrame
;
1469 // If we have just one single inline graphic then
1470 // don't insert a field for the single frame, set
1471 // the frames hyperlink field attribute directly.
1472 pFrame
= SwWW8ImplReader::ContainsSingleInlineGraphic(aRegion
);
1473 if (nullptr != pFrame
)
1475 const SwFormatINetFormat
*pAttr
= static_cast<const SwFormatINetFormat
*>(
1476 rEntry
.m_pAttr
.get());
1478 aURL
.SetURL(pAttr
->GetValue(), false);
1479 aURL
.SetTargetFrameName(pAttr
->GetTargetFrame());
1480 pFrame
->SetFormatAttr(aURL
);
1484 m_rDoc
.getIDocumentContentOperations().InsertPoolItem(aRegion
, *rEntry
.m_pAttr
);
1490 SwFltControlStack::SetAttrInDoc(rTmpPos
, rEntry
);
1495 const SfxPoolItem
* SwWW8FltControlStack::GetFormatAttr(const SwPosition
& rPos
,
1498 const SfxPoolItem
*pItem
= GetStackAttr(rPos
, nWhich
);
1501 SwContentNode
const*const pNd
= rPos
.GetNode().GetContentNode();
1503 pItem
= &m_rDoc
.GetAttrPool().GetUserOrPoolDefaultItem(nWhich
);
1507 If we're hunting for the indent on a paragraph and need to use the
1508 parent style indent, then return the indent in msword format, and
1509 not writer format, because that's the style that the filter works
1512 if (nWhich
== RES_MARGIN_FIRSTLINE
1513 || nWhich
== RES_MARGIN_TEXTLEFT
1514 || nWhich
== RES_MARGIN_RIGHT
)
1516 SfxItemState eState
= SfxItemState::DEFAULT
;
1517 if (const SfxItemSet
*pSet
= pNd
->GetpSwAttrSet())
1518 eState
= pSet
->GetItemState(nWhich
, false);
1519 if (eState
!= SfxItemState::SET
&& m_rReader
.m_nCurrentColl
< m_rReader
.m_vColl
.size())
1523 case RES_MARGIN_FIRSTLINE
:
1524 pItem
= m_rReader
.m_vColl
[m_rReader
.m_nCurrentColl
].m_pWordFirstLine
.get();
1526 case RES_MARGIN_TEXTLEFT
:
1527 pItem
= m_rReader
.m_vColl
[m_rReader
.m_nCurrentColl
].m_pWordLeftMargin
.get();
1529 case RES_MARGIN_RIGHT
:
1530 pItem
= m_rReader
.m_vColl
[m_rReader
.m_nCurrentColl
].m_pWordRightMargin
.get();
1537 If we're hunting for a character property, try and exact position
1538 within the text node for lookup
1540 if (pNd
->IsTextNode())
1542 const sal_Int32 nPos
= rPos
.GetContentIndex();
1543 m_xScratchSet
.reset(new SfxItemSet(m_rDoc
.GetAttrPool(), nWhich
, nWhich
));
1544 if (pNd
->GetTextNode()->GetParaAttr(*m_xScratchSet
, nPos
, nPos
))
1545 pItem
= m_xScratchSet
->GetItem(nWhich
);
1549 pItem
= &pNd
->GetAttr(nWhich
);
1555 const SfxPoolItem
* SwWW8FltControlStack::GetStackAttr(const SwPosition
& rPos
,
1558 SwFltPosition
aFltPos(rPos
);
1560 size_t nSize
= size();
1563 const SwFltStackEntry
& rEntry
= (*this)[ --nSize
];
1564 if (rEntry
.m_pAttr
->Which() == nWhich
)
1566 if ( (rEntry
.m_bOpen
) ||
1568 (rEntry
.m_aMkPos
.m_nNode
<= aFltPos
.m_nNode
) &&
1569 (rEntry
.m_aPtPos
.m_nNode
>= aFltPos
.m_nNode
) &&
1570 (rEntry
.m_aMkPos
.m_nContent
<= aFltPos
.m_nContent
) &&
1571 (rEntry
.m_aPtPos
.m_nContent
> aFltPos
.m_nContent
)
1575 * e.g. half-open range [0-3) so asking for properties at 3
1576 * means props that end at 3 are not included
1579 return rEntry
.m_pAttr
.get();
1586 bool SwWW8FltRefStack::IsFootnoteEdnBkmField(
1587 const SwFormatField
& rFormatField
,
1590 const SwField
* pField
= rFormatField
.GetField();
1591 sal_uInt16 nSubType
;
1592 if(pField
&& (SwFieldIds::GetRef
== pField
->Which())
1593 && ((REF_FOOTNOTE
== (nSubType
= pField
->GetSubType())) || (REF_ENDNOTE
== nSubType
))
1594 && !static_cast<const SwGetRefField
*>(pField
)->GetSetRefName().isEmpty())
1596 const IDocumentMarkAccess
* const pMarkAccess
= m_rDoc
.getIDocumentMarkAccess();
1598 pMarkAccess
->findMark( static_cast<const SwGetRefField
*>(pField
)->GetSetRefName() );
1599 if(ppBkmk
!= pMarkAccess
->getAllMarksEnd())
1601 // find Sequence No of corresponding Foot-/Endnote
1602 rBkmNo
= ppBkmk
- pMarkAccess
->getAllMarksBegin();
1609 void SwWW8FltRefStack::SetAttrInDoc(const SwPosition
& rTmpPos
,
1610 SwFltStackEntry
& rEntry
)
1612 switch (rEntry
.m_pAttr
->Which())
1615 Look up these in our lists of bookmarks that were changed to
1616 variables, and replace the ref field with a var field, otherwise
1617 do normal (?) strange stuff
1619 case RES_TXTATR_FIELD
:
1620 case RES_TXTATR_ANNOTATION
:
1621 case RES_TXTATR_INPUTFIELD
:
1623 SwPaM
aPaM(rEntry
.m_aMkPos
.m_nNode
.GetNode(), SwNodeOffset(1), rEntry
.m_aMkPos
.m_nContent
);
1625 SwFormatField
& rFormatField
= *static_cast<SwFormatField
*>(rEntry
.m_pAttr
.get());
1626 SwField
* pField
= rFormatField
.GetField();
1628 if (!RefToVar(pField
, rEntry
))
1631 if( IsFootnoteEdnBkmField(rFormatField
, nBkmNo
) )
1633 ::sw::mark::MarkBase
const * const pMark
= m_rDoc
.getIDocumentMarkAccess()->getAllMarksBegin()[nBkmNo
];
1635 const SwPosition
& rBkMrkPos
= pMark
->GetMarkPos();
1637 SwTextNode
* pText
= rBkMrkPos
.GetNode().GetTextNode();
1638 if( pText
&& rBkMrkPos
.GetContentIndex() )
1640 SwTextAttr
* const pFootnote
= pText
->GetTextAttrForCharAt(
1641 rBkMrkPos
.GetContentIndex()-1, RES_TXTATR_FTN
);
1644 sal_uInt16 nRefNo
= static_cast<SwTextFootnote
*>(pFootnote
)->GetSeqRefNo();
1646 static_cast<SwGetRefField
*>(pField
)->SetSeqNo( nRefNo
);
1648 if( pFootnote
->GetFootnote().IsEndNote() )
1649 static_cast<SwGetRefField
*>(pField
)->SetSubType(REF_ENDNOTE
);
1655 m_rDoc
.getIDocumentContentOperations().InsertPoolItem(aPaM
, *rEntry
.m_pAttr
);
1656 MoveAttrs(*aPaM
.GetPoint());
1660 SwFltEndStack::SetAttrInDoc(rTmpPos
, rEntry
);
1663 case RES_FLTR_BOOKMARK
:
1664 OSL_ENSURE(false, "EndStck used with non field, not what we want");
1665 SwFltEndStack::SetAttrInDoc(rTmpPos
, rEntry
);
1671 For styles we will do our tabstop arithmetic in word style and adjust them to
1672 writer style after all the styles have been finished and the dust settles as
1673 to what affects what.
1675 For explicit attributes we turn the adjusted writer tabstops back into 0 based
1676 word indexes and we'll turn them back into writer indexes when setting them
1677 into the document. If explicit left indent exist which affects them, then this
1678 is handled when the explicit left indent is set into the document
1680 void SwWW8ImplReader::Read_Tab(sal_uInt16
, const sal_uInt8
* pData
, short nLen
)
1684 m_xCtrlStck
->SetAttr(*m_pPaM
->GetPoint(), RES_PARATR_TABSTOP
);
1688 sal_uInt8 nDel
= (nLen
> 0) ? pData
[0] : 0;
1689 const sal_uInt8
* pDel
= pData
+ 1; // Del - Array
1691 sal_uInt8 nIns
= (nLen
> nDel
*2+1) ? pData
[nDel
*2+1] : 0;
1692 const sal_uInt8
* pIns
= pData
+ 2*nDel
+ 2; // Ins - Array
1694 short nRequiredLength
= 2 + 2*nDel
+ 2*nIns
+ 1*nIns
;
1695 if (nRequiredLength
> nLen
)
1697 // would require more data than available to describe!
1698 // discard invalid record
1703 WW8_TBD
const * pTyp
= reinterpret_cast<WW8_TBD
const *>(pData
+ 2*nDel
+ 2*nIns
+ 2); // Type Array
1705 std::shared_ptr
<SvxTabStopItem
> aAttr(std::make_shared
<SvxTabStopItem
>(0, 0, SvxTabAdjust::Default
, RES_PARATR_TABSTOP
));
1707 const SwFormat
* pSty
= nullptr;
1708 sal_uInt16 nTabBase
;
1709 if (m_pCurrentColl
&& m_nCurrentColl
< m_vColl
.size()) // StyleDef
1711 nTabBase
= m_vColl
[m_nCurrentColl
].m_nBase
;
1712 if (nTabBase
< m_vColl
.size()) // Based On
1713 pSty
= m_vColl
[nTabBase
].m_pFormat
;
1717 nTabBase
= m_nCurrentColl
;
1718 if (m_nCurrentColl
< m_vColl
.size())
1719 pSty
= m_vColl
[m_nCurrentColl
].m_pFormat
;
1720 //TODO: figure out else here
1723 bool bFound
= false;
1724 std::unordered_set
<size_t> aLoopWatch
;
1725 while (pSty
&& !bFound
)
1727 const SvxTabStopItem
* pTabs
;
1728 bFound
= pSty
->GetAttrSet().GetItemState(RES_PARATR_TABSTOP
, false,
1729 &pTabs
) == SfxItemState::SET
;
1732 aAttr
.reset(pTabs
->Clone());
1736 sal_uInt16 nOldTabBase
= nTabBase
;
1737 // If based on another
1738 if (nTabBase
< m_vColl
.size())
1739 nTabBase
= m_vColl
[nTabBase
].m_nBase
;
1742 nTabBase
< m_vColl
.size() &&
1743 nOldTabBase
!= nTabBase
&&
1744 nTabBase
!= ww::stiNil
1747 // #i61789: Stop searching when next style is the same as the
1748 // current one (prevent loop)
1749 aLoopWatch
.insert(reinterpret_cast<size_t>(pSty
));
1750 if (nTabBase
< m_vColl
.size())
1751 pSty
= m_vColl
[nTabBase
].m_pFormat
;
1752 //TODO figure out the else branch
1754 if (aLoopWatch
.find(reinterpret_cast<size_t>(pSty
)) !=
1759 pSty
= nullptr; // Give up on the search
1763 SvxTabStop aTabStop
;
1764 for (short i
=0; i
< nDel
; ++i
)
1766 sal_uInt16 nPos
= aAttr
->GetPos(SVBT16ToUInt16(pDel
+ i
*2));
1767 if( nPos
!= SVX_TAB_NOTFOUND
)
1768 aAttr
->Remove( nPos
);
1771 for (short i
=0; i
< nIns
; ++i
)
1773 short nPos
= SVBT16ToUInt16(pIns
+ i
*2);
1774 aTabStop
.GetTabPos() = nPos
;
1775 switch( pTyp
[i
].aBits1
& 0x7 ) // pTyp[i].jc
1778 aTabStop
.GetAdjustment() = SvxTabAdjust::Left
;
1781 aTabStop
.GetAdjustment() = SvxTabAdjust::Center
;
1784 aTabStop
.GetAdjustment() = SvxTabAdjust::Right
;
1787 aTabStop
.GetAdjustment() = SvxTabAdjust::Decimal
;
1790 continue; // Ignore Bar
1793 switch( pTyp
[i
].aBits1
>> 3 & 0x7 )
1796 aTabStop
.GetFill() = ' ';
1799 aTabStop
.GetFill() = '.';
1802 aTabStop
.GetFill() = '-';
1806 aTabStop
.GetFill() = '_';
1810 sal_uInt16 nPos2
= aAttr
->GetPos( nPos
);
1811 if (nPos2
!= SVX_TAB_NOTFOUND
)
1812 aAttr
->Remove(nPos2
); // Or else Insert() refuses
1813 aAttr
->Insert(aTabStop
);
1820 // Here we have a tab definition which inserts no extra tabs, or deletes
1821 // no existing tabs. An older version of writer is probably the creator
1822 // of the document :-( . So if we are importing a style we can just
1823 // ignore it. But if we are importing into text we cannot as during
1824 // text SwWW8ImplReader::Read_Tab is called at the begin and end of
1825 // the range the attrib affects, and ignoring it would upset the
1827 if (!m_pCurrentColl
) // not importing into a style
1829 SvxTabStopItem aOrig
= pSty
?
1830 pSty
->GetFormatAttr(RES_PARATR_TABSTOP
) :
1831 m_rDoc
.GetAttrPool().GetUserOrPoolDefaultItem(RES_PARATR_TABSTOP
);
1840 void SwWW8ImplReader::ImportDop()
1842 // correct the LastPrinted date in DocumentProperties
1843 uno::Reference
<document::XDocumentPropertiesSupplier
> xDPS(
1844 m_pDocShell
->GetModel(), uno::UNO_QUERY_THROW
);
1845 uno::Reference
<document::XDocumentProperties
> xDocuProps(
1846 xDPS
->getDocumentProperties());
1847 OSL_ENSURE(xDocuProps
.is(), "DocumentProperties is null");
1848 if (xDocuProps
.is())
1850 DateTime
aLastPrinted(
1851 msfilter::util::DTTM2DateTime(m_xWDop
->dttmLastPrint
));
1852 ::util::DateTime uDT
= aLastPrinted
.GetUNODateTime();
1853 xDocuProps
->setPrintDate(uDT
);
1856 // COMPATIBILITY FLAGS START
1858 // #i78951# - remember the unknown compatibility options
1859 // so as to export them out
1860 m_rDoc
.getIDocumentSettingAccess().Setn32DummyCompatibilityOptions1(m_xWDop
->GetCompatibilityOptions());
1861 m_rDoc
.getIDocumentSettingAccess().Setn32DummyCompatibilityOptions2(m_xWDop
->GetCompatibilityOptions2());
1863 // The distance between two paragraphs is the sum of the bottom distance of
1864 // the first paragraph and the top distance of the second one
1865 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::PARA_SPACE_MAX
, m_xWDop
->fDontUseHTMLAutoSpacing
);
1866 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::PARA_SPACE_MAX_AT_PAGES
, true );
1867 // move tabs on alignment
1868 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::TAB_COMPAT
, true);
1869 // #i24363# tab stops relative to indent
1870 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::TABS_RELATIVE_TO_INDENT
, false);
1872 m_rDoc
.getIDocumentSettingAccess().set(
1873 DocumentSettingId::APPLY_PARAGRAPH_MARK_FORMAT_TO_NUMBERING
, true);
1874 m_rDoc
.getIDocumentSettingAccess().set(
1875 DocumentSettingId::MS_WORD_COMP_TRAILING_BLANKS
, true);
1877 m_rDoc
.getIDocumentSettingAccess().set(
1878 DocumentSettingId::HEADER_SPACING_BELOW_LAST_PARA
, true);
1879 m_rDoc
.getIDocumentSettingAccess().set(
1880 DocumentSettingId::FRAME_AUTOWIDTH_WITH_MORE_PARA
, true);
1881 m_rDoc
.getIDocumentSettingAccess().set(
1882 DocumentSettingId::FOOTNOTE_IN_COLUMN_TO_PAGEEND
, true);
1883 m_rDoc
.getIDocumentSettingAccess().set(
1884 DocumentSettingId::EMPTY_DB_FIELD_HIDES_PARA
, false);
1885 // tdf#155229 calculate minimum row height including horizontal border width
1886 m_rDoc
.getIDocumentSettingAccess().set(
1887 DocumentSettingId::MIN_ROW_HEIGHT_INCL_BORDER
, true);
1888 // tdf#129808 use Word-compatible CJK text grid metrics
1889 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::MS_WORD_COMP_GRID_METRICS
, true);
1891 // Import Default Tabs
1892 tools::Long nDefTabSiz
= m_xWDop
->dxaTab
;
1893 if( nDefTabSiz
< 56 )
1896 // We want exactly one DefaultTab
1897 SvxTabStopItem
aNewTab( 1, sal_uInt16(nDefTabSiz
), SvxTabAdjust::Default
, RES_PARATR_TABSTOP
);
1898 const_cast<SvxTabStop
&>(aNewTab
[0]).GetAdjustment() = SvxTabAdjust::Default
;
1900 m_rDoc
.GetAttrPool().SetUserDefaultItem( aNewTab
);
1902 // Import zoom factor
1903 if (m_xWDop
->wScaleSaved
)
1906 sal_Int16 nZoomType
;
1907 switch (m_xWDop
->zkSaved
) {
1908 case 1: nZoomType
= sal_Int16(SvxZoomType::WHOLEPAGE
); break;
1909 case 2: nZoomType
= sal_Int16(SvxZoomType::PAGEWIDTH
); break;
1910 case 3: nZoomType
= sal_Int16(SvxZoomType::OPTIMAL
); break;
1911 default: nZoomType
= sal_Int16(SvxZoomType::PERCENT
); break;
1913 uno::Sequence
<beans::PropertyValue
> aViewProps( comphelper::InitPropertySequence({
1914 { "ZoomFactor", uno::Any(sal_Int16(m_xWDop
->wScaleSaved
)) },
1915 { "VisibleBottom", uno::Any(sal_Int32(0)) },
1916 { "ZoomType", uno::Any(nZoomType
) }
1919 rtl::Reference
< comphelper::IndexedPropertyValuesContainer
> xBox
= new comphelper::IndexedPropertyValuesContainer();
1920 xBox
->insertByIndex(sal_Int32(0), uno::Any(aViewProps
));
1921 uno::Reference
<document::XViewDataSupplier
> xViewDataSupplier(m_pDocShell
->GetModel(), uno::UNO_QUERY
);
1922 xViewDataSupplier
->setViewData(xBox
);
1925 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::USE_VIRTUAL_DEVICE
, !m_xWDop
->fUsePrinterMetrics
);
1926 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::USE_HIRES_VIRTUAL_DEVICE
, true);
1927 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::ADD_FLY_OFFSETS
, true );
1929 // No vertical offsets would lead to e.g. overlap of table and fly frames.
1930 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::ADD_VERTICAL_FLY_OFFSETS
, true );
1932 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::ADD_EXT_LEADING
, !m_xWDop
->fNoLeading
);
1933 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::OLD_NUMBERING
, false);
1934 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING
, false); // #i47448#
1935 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::NO_GAP_AFTER_NOTE_NUMBER
, true); // tdf#159382
1936 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::DO_NOT_JUSTIFY_LINES_WITH_MANUAL_BREAK
, !m_xWDop
->fExpShRtn
); // #i49277#, #i56856#
1937 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::DO_NOT_RESET_PARA_ATTRS_FOR_NUM_FONT
, false); // #i53199#
1938 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::OLD_LINE_SPACING
, false);
1940 // #i25901# - set new compatibility option
1941 // 'Add paragraph and table spacing at bottom of table cells'
1942 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::ADD_PARA_SPACING_TO_TABLE_CELLS
, true);
1943 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::ADD_PARA_LINE_SPACING_TO_TABLE_CELLS
, true);
1945 // #i11860# - set new compatibility option
1946 // 'Use former object positioning' to <false>
1947 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::USE_FORMER_OBJECT_POS
, false);
1949 // #i27767# - set new compatibility option
1950 // 'Consider Wrapping mode when positioning object' to <true>
1951 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION
, true);
1953 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::USE_FORMER_TEXT_WRAPPING
, false); // #i13832#, #i24135#
1955 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::TABLE_ROW_KEEP
, true); //SetTableRowKeep( true );
1957 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::IGNORE_TABS_AND_BLANKS_FOR_LINE_CALCULATION
, true); // #i3952#
1959 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::INVERT_BORDER_SPACING
, true);
1960 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::COLLAPSE_EMPTY_CELL_PARA
, true);
1961 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::UNBREAKABLE_NUMBERINGS
, true);
1962 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::CLIPPED_PICTURES
, true);
1963 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::TAB_OVER_MARGIN
, true);
1964 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::SURROUND_TEXT_WRAP_SMALL
, true);
1965 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::PROP_LINE_SPACING_SHRINKS_FIRST_LINE
, true);
1966 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::CONTINUOUS_ENDNOTES
, true);
1967 // rely on default for HYPHENATE_URLS=false
1968 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::APPLY_PARAGRAPH_MARK_FORMAT_TO_EMPTY_LINE_AT_END_OF_PARAGRAPH
, true);
1969 // rely on default for IGNORE_HIDDEN_CHARS_FOR_LINE_CALCULATION=true
1971 IDocumentSettingAccess
& rIDSA
= m_rDoc
.getIDocumentSettingAccess();
1972 if (m_xWDop
->fDontBreakWrappedTables
)
1974 rIDSA
.set(DocumentSettingId::DO_NOT_BREAK_WRAPPED_TABLES
, true);
1977 // COMPATIBILITY FLAGS END
1979 // Import magic doptypography information, if it's there
1980 if (m_xWwFib
->m_nFib
> 105)
1981 ImportDopTypography(m_xWDop
->doptypography
);
1983 // disable form design mode to be able to use imported controls directly
1984 // #i31239# always disable form design mode, not only in protected docs
1985 uno::Reference
<beans::XPropertySet
> xDocProps(m_pDocShell
->GetModel(), uno::UNO_QUERY
);
1988 uno::Reference
<beans::XPropertySetInfo
> xInfo
= xDocProps
->getPropertySetInfo();
1991 if (xInfo
->hasPropertyByName(u
"ApplyFormDesignMode"_ustr
))
1992 xDocProps
->setPropertyValue(u
"ApplyFormDesignMode"_ustr
, css::uno::Any(false));
1995 // for the benefit of DOCX - if this is ever saved in that format.
1996 comphelper::SequenceAsHashMap
aGrabBag(xDocProps
->getPropertyValue(u
"InteropGrabBag"_ustr
));
1997 uno::Sequence
<beans::PropertyValue
> aCompatSetting( comphelper::InitPropertySequence({
1998 { "name", uno::Any(u
"compatibilityMode"_ustr
) },
1999 { "uri", uno::Any(u
"http://schemas.microsoft.com/office/word"_ustr
) },
2000 { "val", uno::Any(u
"11"_ustr
) } //11: Use features specified in MS-DOC.
2003 uno::Sequence
< beans::PropertyValue
> aValue(comphelper::InitPropertySequence({
2004 { "compatSetting", uno::Any(aCompatSetting
) }
2007 aGrabBag
[u
"CompatSettings"_ustr
] <<= aValue
;
2008 xDocProps
->setPropertyValue(u
"InteropGrabBag"_ustr
, uno::Any(aGrabBag
.getAsConstPropertyValueList()));
2011 // The password can force read-only, comments-only, fill-in-form-only, or require track-changes.
2012 // Treat comments-only like read-only since Writer has no support for that.
2013 // Still allow editing of form fields, without requiring the password.
2014 // Still allow editing if track-changes is locked on. (Currently LockRev is ignored/lost on export anyway.)
2015 if (!m_xWDop
->fProtEnabled
&& !m_xWDop
->fLockRev
)
2016 m_pDocShell
->SetModifyPasswordHash(m_xWDop
->lKeyProtDoc
);
2017 else if ( xDocProps
.is() )
2019 comphelper::SequenceAsHashMap
aGrabBag(xDocProps
->getPropertyValue(u
"InteropGrabBag"_ustr
));
2020 aGrabBag
[u
"FormPasswordHash"_ustr
] <<= m_xWDop
->lKeyProtDoc
;
2021 xDocProps
->setPropertyValue(u
"InteropGrabBag"_ustr
, uno::Any(aGrabBag
.getAsConstPropertyValueList()));
2024 if (officecfg::Office::Common::Filter::Microsoft::Import::ImportWWFieldsAsEnhancedFields::get())
2025 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::PROTECT_FORM
, m_xWDop
->fProtEnabled
);
2027 if (m_xWDop
->iGutterPos
)
2029 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::GUTTER_AT_TOP
, true);
2033 void SwWW8ImplReader::ImportDopTypography(const WW8DopTypography
&rTypo
)
2035 switch (rTypo
.m_iLevelOfKinsoku
)
2039 i18n::ForbiddenCharacters
aForbidden(OUString(+rTypo
.m_rgxchFPunct
),
2040 OUString(+rTypo
.m_rgxchLPunct
));
2041 // unary + makes sure not to accidentally call the deleted
2042 // OUString(ConstCharArrayDetector<...>::TypeUtf16) ctor that takes the full
2043 // m_rgxchFPunct, m_rgxchLPunct arrays with embedded NULs, instead of just the
2044 // prefix leading up to the first NUL
2045 m_rDoc
.getIDocumentSettingAccess().setForbiddenCharacters(rTypo
.GetConvertedLang(),
2047 // Obviously cannot set the standard level 1 for japanese, so
2048 // bail out now while we can.
2049 if (rTypo
.GetConvertedLang() == LANGUAGE_JAPANESE
)
2058 This MS hack means that level 2 of japanese is not in operation, so we put
2059 in what we know are the MS defaults, there is a complementary reverse
2060 hack in the writer. Its our default as well, but we can set it anyway
2061 as a flag for later.
2063 if (!rTypo
.m_reserved2
)
2065 i18n::ForbiddenCharacters
aForbidden(WW8DopTypography::JapanNotBeginLevel1
,
2066 WW8DopTypography::JapanNotEndLevel1
);
2067 m_rDoc
.getIDocumentSettingAccess().setForbiddenCharacters(LANGUAGE_JAPANESE
,aForbidden
);
2070 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::KERN_ASIAN_PUNCTUATION
, bool(rTypo
.m_fKerningPunct
));
2071 m_rDoc
.getIDocumentSettingAccess().setCharacterCompressionType(static_cast<CharCompressType
>(rTypo
.m_iJustification
));
2075 * Footnotes and Endnotes
2077 WW8ReaderSave::WW8ReaderSave(SwWW8ImplReader
* pRdr
,WW8_CP nStartCp
) :
2078 mxTmpPos(pRdr
->m_rDoc
.CreateUnoCursor(*pRdr
->m_pPaM
->GetPoint())),
2079 mxOldStck(std::move(pRdr
->m_xCtrlStck
)),
2080 mxOldAnchorStck(std::move(pRdr
->m_xAnchorStck
)),
2081 mxOldRedlines(std::move(pRdr
->m_xRedlineStack
)),
2082 mxOldPlcxMan(pRdr
->m_xPlcxMan
),
2083 mpWFlyPara(std::move(pRdr
->m_xWFlyPara
)),
2084 mpSFlyPara(std::move(pRdr
->m_xSFlyPara
)),
2085 mpPreviousNumPaM(pRdr
->m_pPreviousNumPaM
),
2086 mpPrevNumRule(pRdr
->m_pPrevNumRule
),
2087 mxTableDesc(std::move(pRdr
->m_xTableDesc
)),
2088 mnInTable(pRdr
->m_nInTable
),
2089 mnCurrentColl(pRdr
->m_nCurrentColl
),
2090 mcSymbol(pRdr
->m_cSymbol
),
2091 mbIgnoreText(pRdr
->m_bIgnoreText
),
2092 mbSymbol(pRdr
->m_bSymbol
),
2093 mbHdFtFootnoteEdn(pRdr
->m_bHdFtFootnoteEdn
),
2094 mbTxbxFlySection(pRdr
->m_bTxbxFlySection
),
2095 mbAnl(pRdr
->m_bAnl
),
2096 mbInHyperlink(pRdr
->m_bInHyperlink
),
2097 mbPgSecBreak(pRdr
->m_bPgSecBreak
),
2098 mbWasParaEnd(pRdr
->m_bWasParaEnd
),
2099 mbHasBorder(pRdr
->m_bHasBorder
),
2100 mbFirstPara(pRdr
->m_bFirstPara
)
2102 pRdr
->m_bSymbol
= false;
2103 pRdr
->m_bHdFtFootnoteEdn
= true;
2104 pRdr
->m_bTxbxFlySection
= pRdr
->m_bAnl
= pRdr
->m_bPgSecBreak
= pRdr
->m_bWasParaEnd
2105 = pRdr
->m_bHasBorder
= false;
2106 pRdr
->m_bFirstPara
= true;
2107 pRdr
->m_nInTable
= 0;
2108 pRdr
->m_pPreviousNumPaM
= nullptr;
2109 pRdr
->m_pPrevNumRule
= nullptr;
2110 pRdr
->m_nCurrentColl
= 0;
2112 pRdr
->m_xCtrlStck
.reset(new SwWW8FltControlStack(pRdr
->m_rDoc
, pRdr
->m_nFieldFlags
,
2115 pRdr
->m_xRedlineStack
.reset(new sw::util::RedlineStack(pRdr
->m_rDoc
));
2117 pRdr
->m_xAnchorStck
.reset(new SwWW8FltAnchorStack(pRdr
->m_rDoc
, pRdr
->m_nFieldFlags
));
2119 // Save the attribute manager: we need this as the newly created PLCFx Manager
2120 // access the same FKPs as the old one and their Start-End position changes.
2121 if (pRdr
->m_xPlcxMan
)
2122 pRdr
->m_xPlcxMan
->SaveAllPLCFx(maPLCFxSave
);
2126 pRdr
->m_xPlcxMan
= std::make_shared
<WW8PLCFMan
>(pRdr
->m_xSBase
.get(),
2127 mxOldPlcxMan
->GetManType(), nStartCp
);
2130 maOldApos
.push_back(false);
2131 maOldApos
.swap(pRdr
->m_aApos
);
2132 maOldFieldStack
.swap(pRdr
->m_aFieldStack
);
2135 void WW8ReaderSave::Restore( SwWW8ImplReader
* pRdr
)
2137 pRdr
->m_xWFlyPara
= std::move(mpWFlyPara
);
2138 pRdr
->m_xSFlyPara
= std::move(mpSFlyPara
);
2139 pRdr
->m_pPreviousNumPaM
= mpPreviousNumPaM
;
2140 pRdr
->m_pPrevNumRule
= mpPrevNumRule
;
2141 pRdr
->m_xTableDesc
= std::move(mxTableDesc
);
2142 pRdr
->m_cSymbol
= mcSymbol
;
2143 pRdr
->m_bSymbol
= mbSymbol
;
2144 pRdr
->m_bIgnoreText
= mbIgnoreText
;
2145 pRdr
->m_bHdFtFootnoteEdn
= mbHdFtFootnoteEdn
;
2146 pRdr
->m_bTxbxFlySection
= mbTxbxFlySection
;
2147 pRdr
->m_nInTable
= mnInTable
;
2148 pRdr
->m_bAnl
= mbAnl
;
2149 pRdr
->m_bInHyperlink
= mbInHyperlink
;
2150 pRdr
->m_bWasParaEnd
= mbWasParaEnd
;
2151 pRdr
->m_bPgSecBreak
= mbPgSecBreak
;
2152 pRdr
->m_nCurrentColl
= mnCurrentColl
;
2153 pRdr
->m_bHasBorder
= mbHasBorder
;
2154 pRdr
->m_bFirstPara
= mbFirstPara
;
2156 // Close all attributes as attributes could be created that extend the Fly
2157 pRdr
->DeleteCtrlStack();
2158 pRdr
->m_xCtrlStck
= std::move(mxOldStck
);
2160 pRdr
->m_xRedlineStack
->closeall(*pRdr
->m_pPaM
->GetPoint());
2162 // ofz#37322 drop m_oLastAnchorPos during RedlineStack dtor and restore it afterwards to the same
2163 // place, or somewhere close if that place got destroyed
2164 std::shared_ptr
<SwUnoCursor
> xLastAnchorCursor(pRdr
->m_oLastAnchorPos
? pRdr
->m_rDoc
.CreateUnoCursor(*pRdr
->m_oLastAnchorPos
) : nullptr);
2165 pRdr
->m_oLastAnchorPos
.reset();
2167 pRdr
->m_xRedlineStack
= std::move(mxOldRedlines
);
2169 if (xLastAnchorCursor
)
2170 pRdr
->m_oLastAnchorPos
.emplace(*xLastAnchorCursor
->GetPoint());
2172 pRdr
->DeleteAnchorStack();
2173 pRdr
->m_xAnchorStck
= std::move(mxOldAnchorStck
);
2175 *pRdr
->m_pPaM
->GetPoint() = GetStartPos();
2177 if (mxOldPlcxMan
!= pRdr
->m_xPlcxMan
)
2178 pRdr
->m_xPlcxMan
= mxOldPlcxMan
;
2179 if (pRdr
->m_xPlcxMan
)
2180 pRdr
->m_xPlcxMan
->RestoreAllPLCFx(maPLCFxSave
);
2181 pRdr
->m_aApos
.swap(maOldApos
);
2182 pRdr
->m_aFieldStack
.swap(maOldFieldStack
);
2185 void SwWW8ImplReader::Read_HdFtFootnoteText( const SwNodeIndex
* pSttIdx
,
2186 WW8_CP nStartCp
, WW8_CP nLen
, ManTypes nType
)
2188 if (nStartCp
< 0 || nLen
< 0)
2191 // Saves Flags (amongst other things) and resets them
2192 WW8ReaderSave
aSave( this );
2194 m_pPaM
->GetPoint()->Assign( pSttIdx
->GetIndex() + 1 );
2196 // Read Text for Header, Footer or Footnote
2197 ReadText( nStartCp
, nLen
, nType
); // Ignore Sepx when doing so
2198 aSave
.Restore( this );
2202 * Use authornames, if not available fall back to initials.
2204 tools::Long
SwWW8ImplReader::Read_And(WW8PLCFManResult
* pRes
)
2206 WW8PLCFx_SubDoc
* pSD
= m_xPlcxMan
->GetAtn();
2210 const void* pData
= pSD
->GetData();
2218 const WW67_ATRD
* pDescri
= static_cast<const WW67_ATRD
*>(pData
);
2219 const OUString
* pA
= GetAnnotationAuthor(SVBT16ToUInt16(pDescri
->ibst
));
2224 const sal_uInt8 nLen
= std::min
<sal_uInt8
>(pDescri
->xstUsrInitl
[0],
2225 SAL_N_ELEMENTS(pDescri
->xstUsrInitl
)-1);
2226 sAuthor
= OUString(pDescri
->xstUsrInitl
+ 1, nLen
, RTL_TEXTENCODING_MS_1252
);
2231 const WW8_ATRD
* pDescri
= static_cast<const WW8_ATRD
*>(pData
);
2233 const sal_uInt16 nLen
= std::min
<sal_uInt16
>(SVBT16ToUInt16(pDescri
->xstUsrInitl
[0]),
2234 SAL_N_ELEMENTS(pDescri
->xstUsrInitl
)-1);
2235 OUStringBuffer aBuf
;
2236 aBuf
.setLength(nLen
);
2237 for(sal_uInt16 nIdx
= 1; nIdx
<= nLen
; ++nIdx
)
2238 aBuf
[nIdx
-1] = SVBT16ToUInt16(pDescri
->xstUsrInitl
[nIdx
]);
2239 sInitials
= aBuf
.makeStringAndClear();
2242 if (const OUString
* pA
= GetAnnotationAuthor(SVBT16ToUInt16(pDescri
->ibst
)))
2245 sAuthor
= sInitials
;
2248 sal_uInt32 nDateTime
= 0;
2250 if (sal_uInt8
* pExtended
= m_xPlcxMan
->GetExtendedAtrds()) // Word < 2002 has no date data for comments
2252 sal_uLong nIndex
= pSD
->GetIdx() & 0xFFFF; // Index is (stupidly) multiplexed for WW8PLCFx_SubDocs
2253 if (m_xWwFib
->m_lcbAtrdExtra
/18 > nIndex
)
2254 nDateTime
= SVBT32ToUInt32(*reinterpret_cast<SVBT32
*>(pExtended
+(nIndex
*18)));
2257 DateTime aDate
= msfilter::util::DTTM2DateTime(nDateTime
);
2260 std::optional
<OutlinerParaObject
> pOutliner
= ImportAsOutliner( sText
, pRes
->nCp2OrIdx
,
2261 pRes
->nCp2OrIdx
+ pRes
->nMemLen
, MAN_AND
);
2263 m_xFormatOfJustInsertedApo
.reset();
2264 SwPostItField
aPostIt(
2265 static_cast<SwPostItFieldType
*>(m_rDoc
.getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::Postit
)), sAuthor
,
2266 sText
, sInitials
, OUString(), aDate
);
2267 aPostIt
.SetTextObject(std::move(pOutliner
));
2269 SwPaM
aEnd(*m_pPaM
->End(), *m_pPaM
->End());
2270 m_xCtrlStck
->NewAttr(*aEnd
.GetPoint(), SvxCharHiddenItem(false, RES_CHRATR_HIDDEN
));
2271 m_rDoc
.getIDocumentContentOperations().InsertPoolItem(aEnd
, SwFormatField(aPostIt
));
2272 m_xCtrlStck
->SetAttr(*aEnd
.GetPoint(), RES_CHRATR_HIDDEN
);
2273 // If this is a range, make sure that it ends after the just inserted character, not before it.
2274 m_xReffedStck
->MoveAttrs(*aEnd
.GetPoint(), SwFltControlStack::MoveAttrsMode::POSTIT_INSERTED
);
2279 void SwWW8ImplReader::Read_HdFtTextAsHackedFrame(WW8_CP nStart
, WW8_CP nLen
,
2280 SwFrameFormat
const &rHdFtFormat
, sal_uInt16 nPageWidth
)
2282 const SwNodeIndex
* pSttIdx
= rHdFtFormat
.GetContent().GetContentIdx();
2283 OSL_ENSURE(pSttIdx
, "impossible");
2287 SwPosition
aTmpPos(*m_pPaM
->GetPoint());
2289 m_pPaM
->GetPoint()->Assign( pSttIdx
->GetIndex() + 1 );
2291 // tdf#122425: Explicitly remove borders and spacing
2292 SfxItemSetFixed
<RES_FRMATR_BEGIN
, RES_FRMATR_END
- 1> aFlySet(m_rDoc
.GetAttrPool());
2293 Reader::ResetFrameFormatAttrs(aFlySet
);
2295 SwFlyFrameFormat
* pFrame
2296 = m_rDoc
.MakeFlySection(RndStdIds::FLY_AT_PARA
, m_pPaM
->GetPoint(), &aFlySet
);
2298 SwFormatAnchor
aAnch( pFrame
->GetAnchor() );
2299 aAnch
.SetType( RndStdIds::FLY_AT_PARA
);
2300 pFrame
->SetFormatAttr( aAnch
);
2301 SwFormatFrameSize
aSz(SwFrameSize::Minimum
, nPageWidth
, MINLAY
);
2302 SwFrameSize eFrameSize
= SwFrameSize::Minimum
;
2303 if( eFrameSize
!= aSz
.GetWidthSizeType() )
2304 aSz
.SetWidthSizeType( eFrameSize
);
2305 pFrame
->SetFormatAttr(aSz
);
2306 pFrame
->SetFormatAttr(SwFormatSurround(css::text::WrapTextMode_THROUGH
));
2307 pFrame
->SetFormatAttr(SwFormatHoriOrient(0, text::HoriOrientation::LEFT
)); //iFOO
2309 // #i43427# - send frame for header/footer into background.
2310 pFrame
->SetFormatAttr( SvxOpaqueItem( RES_OPAQUE
, false ) );
2311 SdrObject
* pFrameObj
= CreateContactObject( pFrame
);
2312 OSL_ENSURE( pFrameObj
,
2313 "<SwWW8ImplReader::Read_HdFtTextAsHackedFrame(..)> - missing SdrObject instance" );
2316 pFrameObj
->SetOrdNum( 0 );
2318 MoveInsideFly(pFrame
);
2320 const SwNodeIndex
* pHackIdx
= pFrame
->GetContent().GetContentIdx();
2322 Read_HdFtFootnoteText(pHackIdx
, nStart
, nLen
- 1, MAN_HDFT
);
2324 MoveOutsideFly(pFrame
, aTmpPos
);
2327 void SwWW8ImplReader::Read_HdFtText(WW8_CP nStart
, WW8_CP nLen
, SwFrameFormat
const * pHdFtFormat
)
2329 const SwNodeIndex
* pSttIdx
= pHdFtFormat
->GetContent().GetContentIdx();
2333 SwPosition
aTmpPos( *m_pPaM
->GetPoint() ); // Remember old cursor position
2335 Read_HdFtFootnoteText(pSttIdx
, nStart
, nLen
- 1, MAN_HDFT
);
2337 *m_pPaM
->GetPoint() = std::move(aTmpPos
);
2340 bool SwWW8ImplReader::isValid_HdFt_CP(WW8_CP nHeaderCP
) const
2342 // Each CP of Plcfhdd MUST be less than FibRgLw97.ccpHdd
2343 return (nHeaderCP
< m_xWwFib
->m_ccpHdr
&& nHeaderCP
>= 0);
2346 bool SwWW8ImplReader::HasOwnHeaderFooter(sal_uInt8 nWhichItems
, sal_uInt8 grpfIhdt
,
2351 WW8_CP nStart
, nLen
;
2352 sal_uInt8 nNumber
= 5;
2354 for( sal_uInt8 nI
= 0x20; nI
; nI
>>= 1, nNumber
-- )
2356 if (nI
& nWhichItems
)
2360 bOk
= ( m_xHdFt
->GetTextPos(grpfIhdt
, nI
, nStart
, nLen
) && nStart
>= 0 && nLen
>= 2 );
2363 m_xHdFt
->GetTextPosExact( static_cast< short >(nNumber
+ (nSect
+1)*6), nStart
, nLen
);
2364 bOk
= ( 2 <= nLen
) && isValid_HdFt_CP(nStart
);
2375 void SwWW8ImplReader::Read_HdFt(int nSect
, const SwPageDesc
*pPrev
,
2376 const wwSection
&rSection
)
2378 sal_uInt8 grpfIhdt
= rSection
.maSep
.grpfIhdt
;
2379 SwPageDesc
*pPD
= rSection
.mpPage
;
2384 WW8_CP nStart
, nLen
;
2385 sal_uInt8 nNumber
= 5;
2387 // This loops through the 6 flags WW8_{FOOTER,HEADER}_{ODD,EVEN,FIRST}
2388 // corresponding to bit fields in grpfIhdt indicating which
2389 // header/footer(s) are present in this section
2390 for( sal_uInt8 nI
= 0x20; nI
; nI
>>= 1, nNumber
-- )
2396 bOk
= ( m_xHdFt
->GetTextPos(grpfIhdt
, nI
, nStart
, nLen
) && nLen
>= 2 );
2399 m_xHdFt
->GetTextPosExact( static_cast< short >(nNumber
+ (nSect
+1)*6), nStart
, nLen
);
2400 bOk
= ( 2 <= nLen
) && isValid_HdFt_CP(nStart
);
2404 = (nI
& ( WW8_HEADER_EVEN
| WW8_FOOTER_EVEN
)) != 0;
2406 = (nI
& ( WW8_HEADER_FIRST
| WW8_FOOTER_FIRST
)) != 0;
2408 // If we are loading a first-page header/footer which is not
2409 // actually enabled in this section (it still needs to be
2410 // loaded as it may be inherited by a later section)
2411 bool bDisabledFirst
= bUseFirst
&& !rSection
.HasTitlePage();
2414 = (nI
& ( WW8_FOOTER_EVEN
| WW8_FOOTER_ODD
| WW8_FOOTER_FIRST
)) != 0;
2416 SwFrameFormat
& rFormat
= bUseLeft
? pPD
->GetLeft()
2417 : bUseFirst
? pPD
->GetFirstMaster()
2420 SwFrameFormat
* pHdFtFormat
;
2421 // If we have empty first page header and footer.
2422 bool bNoFirst
= !(grpfIhdt
& WW8_HEADER_FIRST
) && !(grpfIhdt
& WW8_FOOTER_FIRST
);
2426 //#i17196# Cannot have left without right
2428 && !pPD
->GetMaster().GetFooter().GetFooterFormat())
2429 pPD
->GetMaster().SetFormatAttr(SwFormatFooter(true));
2431 pPD
->GetLeft().SetFormatAttr(SwFormatFooter(true));
2432 if (bUseFirst
|| (rSection
.maSep
.fTitlePage
&& bNoFirst
))
2433 pPD
->GetFirstMaster().SetFormatAttr(SwFormatFooter(true));
2434 pHdFtFormat
= const_cast<SwFrameFormat
*>(rFormat
.GetFooter().GetFooterFormat());
2439 //#i17196# Cannot have left without right
2441 && !pPD
->GetMaster().GetHeader().GetHeaderFormat())
2442 pPD
->GetMaster().SetFormatAttr(SwFormatHeader(true));
2444 pPD
->GetLeft().SetFormatAttr(SwFormatHeader(true));
2445 if (bUseFirst
|| (rSection
.maSep
.fTitlePage
&& bNoFirst
))
2446 pPD
->GetFirstMaster().SetFormatAttr(SwFormatHeader(true));
2447 pHdFtFormat
= const_cast<SwFrameFormat
*>(rFormat
.GetHeader().GetHeaderFormat());
2452 bool bHackRequired
= false;
2453 if (m_bIsHeader
&& rSection
.IsFixedHeightHeader())
2454 bHackRequired
= true;
2455 else if (m_bIsFooter
&& rSection
.IsFixedHeightFooter())
2456 bHackRequired
= true;
2460 Read_HdFtTextAsHackedFrame(nStart
, nLen
, *pHdFtFormat
,
2461 static_cast< sal_uInt16
>(rSection
.GetTextAreaWidth()) );
2464 Read_HdFtText(nStart
, nLen
, pHdFtFormat
);
2467 CopyPageDescHdFt(pPrev
, pPD
, nI
);
2469 m_bIsHeader
= m_bIsFooter
= false;
2474 bool wwSectionManager::SectionIsProtected(const wwSection
&rSection
) const
2476 return ( mrReader
.m_xWDop
->fProtEnabled
&& !rSection
.IsNotProtected() );
2479 void wwSectionManager::SetHdFt(wwSection
const &rSection
, int nSect
,
2480 const wwSection
*pPrevious
)
2482 // Header/Footer not present
2483 if (!rSection
.maSep
.grpfIhdt
)
2486 OSL_ENSURE(rSection
.mpPage
, "makes no sense to call with a main page");
2487 if (rSection
.mpPage
)
2489 mrReader
.Read_HdFt(nSect
, pPrevious
? pPrevious
->mpPage
: nullptr,
2493 // Header/Footer - Update Index
2494 // So that the index is still valid later on
2495 if (mrReader
.m_xHdFt
)
2496 mrReader
.m_xHdFt
->UpdateIndex(rSection
.maSep
.grpfIhdt
);
2500 void SwWW8ImplReader::FinalizeTextNode(SwPosition
& rPos
, bool bAddNew
)
2502 SwTextNode
* pText
= m_pPaM
->GetPointNode().GetTextNode();
2504 const SwNumRule
* pRule
= nullptr;
2506 if (pText
!= nullptr)
2507 pRule
= sw::util::GetNumRuleFromTextNode(*pText
);
2509 // tdf#64222 / tdf#150613 filter out the "paragraph marker" formatting and
2510 // set it as a separate paragraph property, just like we do for DOCX.
2511 // This is only being used for numbering currently, so limiting to that context.
2514 SfxItemSetFixed
<RES_CHRATR_BEGIN
, RES_CHRATR_END
- 1, RES_TXTATR_CHARFMT
,
2515 RES_TXTATR_CHARFMT
, RES_UNKNOWNATR_BEGIN
, RES_UNKNOWNATR_END
- 1>
2516 items(m_pPaM
->GetDoc().GetAttrPool());
2518 SfxWhichIter
aIter(items
);
2519 for (sal_uInt16 nWhich
= aIter
.FirstWhich(); nWhich
; nWhich
= aIter
.NextWhich())
2521 const SfxPoolItem
* pItem
= m_xCtrlStck
->GetStackAttr(rPos
, nWhich
);
2525 SwFormatAutoFormat
item(RES_PARATR_LIST_AUTOFMT
);
2526 item
.SetStyleHandle(std::make_shared
<SfxItemSet
>(items
));
2527 pText
->SetAttr(item
);
2531 pRule
&& !m_xWDop
->fDontUseHTMLAutoSpacing
&&
2532 (m_bParaAutoBefore
|| m_bParaAutoAfter
)
2535 // If after spacing is set to auto, set the after space to 0
2536 if (m_bParaAutoAfter
)
2537 SetLowerSpacing(*m_pPaM
, 0);
2539 // If the previous textnode had numbering and
2540 // and before spacing is set to auto, set before space to 0
2541 if(m_pPrevNumRule
&& m_bParaAutoBefore
)
2542 SetUpperSpacing(*m_pPaM
, 0);
2544 // If the previous numbering rule was different we need
2545 // to insert a space after the previous paragraph
2546 if((pRule
!= m_pPrevNumRule
) && m_pPreviousNumPaM
)
2547 SetLowerSpacing(*m_pPreviousNumPaM
, GetParagraphAutoSpace(m_xWDop
->fDontUseHTMLAutoSpacing
));
2549 // cache current paragraph
2550 if(m_pPreviousNumPaM
)
2552 delete m_pPreviousNumPaM
;
2553 m_pPreviousNumPaM
= nullptr;
2556 m_pPreviousNumPaM
= new SwPaM(*m_pPaM
, m_pPaM
);
2557 m_pPrevNumRule
= pRule
;
2559 else if(!pRule
&& m_pPreviousNumPaM
)
2561 // If the previous paragraph has numbering but the current one does not
2562 // we need to add a space after the previous paragraph
2563 SetLowerSpacing(*m_pPreviousNumPaM
, GetParagraphAutoSpace(m_xWDop
->fDontUseHTMLAutoSpacing
));
2564 delete m_pPreviousNumPaM
;
2565 m_pPreviousNumPaM
= nullptr;
2566 m_pPrevNumRule
= nullptr;
2570 // clear paragraph cache
2571 if(m_pPreviousNumPaM
)
2573 delete m_pPreviousNumPaM
;
2574 m_pPreviousNumPaM
= nullptr;
2576 m_pPrevNumRule
= pRule
;
2579 // If this is the first paragraph in the document and
2580 // Auto-spacing before paragraph is set,
2581 // set the upper spacing value to 0
2582 if(m_bParaAutoBefore
&& m_bFirstPara
&& !m_xWDop
->fDontUseHTMLAutoSpacing
)
2583 SetUpperSpacing(*m_pPaM
, 0);
2585 m_bFirstPara
= false;
2588 m_rDoc
.getIDocumentContentOperations().AppendTextNode(rPos
);
2590 // We can flush all anchored graphics at the end of a paragraph.
2591 m_xAnchorStck
->Flush();
2594 bool SwWW8ImplReader::SetSpacing(SwPaM
&rMyPam
, int nSpace
, bool bIsUpper
)
2597 const SwPosition
* pSpacingPos
= rMyPam
.GetPoint();
2599 const SvxULSpaceItem
* pULSpaceItem
= m_xCtrlStck
->GetFormatAttr(*pSpacingPos
, RES_UL_SPACE
);
2601 if(pULSpaceItem
!= nullptr)
2603 SvxULSpaceItem
aUL(*pULSpaceItem
);
2606 aUL
.SetUpper( static_cast< sal_uInt16
>(nSpace
) );
2608 aUL
.SetLower( static_cast< sal_uInt16
>(nSpace
) );
2610 const sal_Int32 nEnd
= pSpacingPos
->GetContentIndex();
2611 rMyPam
.GetPoint()->SetContent(0);
2612 m_xCtrlStck
->NewAttr(*pSpacingPos
, aUL
);
2613 rMyPam
.GetPoint()->SetContent(nEnd
);
2614 m_xCtrlStck
->SetAttr(*pSpacingPos
, RES_UL_SPACE
);
2620 bool SwWW8ImplReader::SetLowerSpacing(SwPaM
&rMyPam
, int nSpace
)
2622 return SetSpacing(rMyPam
, nSpace
, false);
2625 bool SwWW8ImplReader::SetUpperSpacing(SwPaM
&rMyPam
, int nSpace
)
2627 return SetSpacing(rMyPam
, nSpace
, true);
2630 sal_uInt16
SwWW8ImplReader::TabRowSprm(int nLevel
) const
2633 return NS_sprm::v6::sprmPTtp
;
2634 return nLevel
? NS_sprm::PFInnerTtp::val
: NS_sprm::PFTtp::val
;
2637 void SwWW8ImplReader::EndSpecial()
2641 StopAllAnl(); // -> bAnl = false
2643 while(m_aApos
.size() > 1)
2648 if (m_aApos
[m_nInTable
])
2655 OSL_ENSURE(!m_nInTable
, "unclosed table!");
2658 bool SwWW8ImplReader::ProcessSpecial(bool &rbReSync
, WW8_CP nStartCp
)
2666 OSL_ENSURE(m_nInTable
>= 0,"nInTable < 0!");
2669 bool bTableRowEnd
= (m_xPlcxMan
->HasParaSprm(m_bVer67
? 25 : 0x2417).pSprm
!= nullptr);
2671 // Unfortunately, for every paragraph we need to check first whether
2672 // they contain a sprm 29 (0x261B), which starts an APO.
2673 // All other sprms then refer to that APO and not to the normal text
2675 // The same holds true for a Table (sprm 24 (0x2416)) and Anls (sprm 13).
2677 // WW: Table in APO is possible (Both Start-Ends occur at the same time)
2678 // WW: APO in Table not possible
2680 // This mean that of a Table is the content of an APO, the APO start needs
2681 // to be edited first, so that the Table remains in the APO and not the
2682 // other way around.
2683 // At the End, however, we need to edit the Table End first as the APO
2684 // must end after that Table (or else we never find the APO End).
2686 // The same holds true for Fly / Anl, Tab / Anl, Fly / Tab / Anl.
2688 // If the Table is within an APO the TabRowEnd Area misses the
2690 // To not end the APO there, we do not call ProcessApo
2692 // KHZ: When there is a table inside the Apo the Apo-flags are also
2693 // missing for the 2nd, 3rd... paragraphs of each cell.
2695 // 1st look for in-table flag, for 2000+ there is a subtable flag to
2696 // be considered, the sprm 6649 gives the level of the table
2697 sal_uInt8 nCellLevel
= 0;
2700 nCellLevel
= int(nullptr != m_xPlcxMan
->HasParaSprm(24).pSprm
);
2703 nCellLevel
= int(nullptr != m_xPlcxMan
->HasParaSprm(0x2416).pSprm
);
2705 nCellLevel
= int(nullptr != m_xPlcxMan
->HasParaSprm(0x244B).pSprm
);
2709 WW8_TablePos
*pTabPos
=nullptr;
2710 WW8_TablePos aTabPos
;
2711 if(nCellLevel
&& !m_bVer67
)
2713 WW8PLCFxSave1 aSave
;
2714 m_xPlcxMan
->GetPap()->Save( aSave
);
2716 WW8PLCFx_Cp_FKP
* pPap
= m_xPlcxMan
->GetPapPLCF();
2717 WW8_CP nMyStartCp
=nStartCp
;
2719 SprmResult aLevel
= m_xPlcxMan
->HasParaSprm(0x6649);
2720 if (aLevel
.pSprm
&& aLevel
.nRemainingData
>= 1)
2721 nCellLevel
= *aLevel
.pSprm
;
2723 bool bHasRowEnd
= SearchRowEnd(pPap
, nMyStartCp
, (m_nInTable
<nCellLevel
?m_nInTable
:nCellLevel
-1));
2725 // Bad Table, remain unchanged in level, e.g. #i19667#
2727 nCellLevel
= static_cast< sal_uInt8
>(m_nInTable
);
2729 if (bHasRowEnd
&& ParseTabPos(&aTabPos
,pPap
))
2732 m_xPlcxMan
->GetPap()->Restore( aSave
);
2735 // Then look if we are in an Apo
2737 ApoTestResults aApo
= TestApo(nCellLevel
, bTableRowEnd
, pTabPos
);
2739 // Look to see if we are in a Table, but Table in foot/end note not allowed
2740 bool bStartTab
= (m_nInTable
< nCellLevel
) && !m_bFootnoteEdn
;
2742 bool bStopTab
= m_bWasTabRowEnd
&& (m_nInTable
> nCellLevel
) && !m_bFootnoteEdn
;
2744 m_bWasTabRowEnd
= false; // must be deactivated right here to prevent next
2745 // WW8TabDesc::TableCellEnd() from making nonsense
2747 if (m_nInTable
&& !bTableRowEnd
&& !bStopTab
&& (m_nInTable
== nCellLevel
&& aApo
.HasStartStop()))
2748 bStopTab
= bStartTab
= true; // Required to stop and start table
2750 // Test for Anl (Numbering) and process all events in the right order
2751 if( m_bAnl
&& !bTableRowEnd
)
2753 SprmResult aSprm13
= m_xPlcxMan
->HasParaSprm(13);
2754 const sal_uInt8
* pSprm13
= aSprm13
.pSprm
;
2755 if (pSprm13
&& aSprm13
.nRemainingData
>= 1)
2756 { // Still Anl left?
2757 sal_uInt8 nT
= static_cast< sal_uInt8
>(GetNumType( *pSprm13
));
2758 if( ( nT
!= WW8_Pause
&& nT
!= m_nWwNumType
) // Anl change
2759 || aApo
.HasStartStop() // Forced Anl end
2760 || bStopTab
|| bStartTab
)
2762 StopAnlToRestart(nT
); // Anl-Restart (= change) over sprms
2766 NextAnlLine( pSprm13
); // Next Anl Line
2770 { // Regular Anl end
2771 StopAllAnl(); // Actual end
2783 m_aApos
[m_nInTable
] = false;
2786 if (aApo
.mbStartApo
)
2788 m_aApos
[m_nInTable
] = StartApo(aApo
, pTabPos
);
2789 // We need an ReSync after StartApo
2790 // (actually only if the Apo extends past a FKP border)
2795 WW8PLCFxSave1 aSave
;
2796 m_xPlcxMan
->GetPap()->Save( aSave
);
2798 // Numbering for cell borders causes a crash -> no Anls in Tables
2802 if(m_nInTable
< nCellLevel
)
2804 if (StartTable(nStartCp
))
2808 m_aApos
.push_back(false);
2811 if(m_nInTable
>= nCellLevel
)
2813 // We need an ReSync after StartTable
2814 // (actually only if the Apo extends past a FKP border)
2816 m_xPlcxMan
->GetPap()->Restore( aSave
);
2819 } while (!m_bFootnoteEdn
&& (m_nInTable
< nCellLevel
));
2820 return bTableRowEnd
;
2823 rtl_TextEncoding
SwWW8ImplReader::GetCharSetFromLanguage()
2827 The (default) character set used for a run of text is the default
2828 character set for the version of Word that last saved the document.
2830 This is a bit tentative, more might be required if the concept is correct.
2831 When later version of word write older 6/95 documents the charset is
2832 correctly set in the character runs involved, so it's hard to reproduce
2833 documents that require this to be sure of the process involved.
2835 const SvxLanguageItem
*pLang
= GetFormatAttr(RES_CHRATR_LANGUAGE
);
2836 LanguageType eLang
= pLang
? pLang
->GetLanguage() : LANGUAGE_SYSTEM
;
2837 css::lang::Locale
aLocale(LanguageTag::convertToLocale(eLang
));
2838 return msfilter::util::getBestTextEncodingFromLocale(aLocale
);
2841 rtl_TextEncoding
SwWW8ImplReader::GetCJKCharSetFromLanguage()
2845 The (default) character set used for a run of text is the default
2846 character set for the version of Word that last saved the document.
2848 This is a bit tentative, more might be required if the concept is correct.
2849 When later version of word write older 6/95 documents the charset is
2850 correctly set in the character runs involved, so it's hard to reproduce
2851 documents that require this to be sure of the process involved.
2853 const SvxLanguageItem
*pLang
= GetFormatAttr(RES_CHRATR_CJK_LANGUAGE
);
2854 LanguageType eLang
= pLang
? pLang
->GetLanguage() : LANGUAGE_SYSTEM
;
2855 css::lang::Locale
aLocale(LanguageTag::convertToLocale(eLang
));
2856 return msfilter::util::getBestTextEncodingFromLocale(aLocale
);
2859 rtl_TextEncoding
SwWW8ImplReader::GetCurrentCharSet()
2863 If the hard charset is set use it, if not see if there is an open
2864 character run that has set the charset, if not then fallback to the
2865 current underlying paragraph style.
2867 rtl_TextEncoding eSrcCharSet
= m_eHardCharSet
;
2868 if (eSrcCharSet
== RTL_TEXTENCODING_DONTKNOW
)
2871 eSrcCharSet
= GetCharSetFromLanguage();
2872 else if (!m_aFontSrcCharSets
.empty())
2873 eSrcCharSet
= m_aFontSrcCharSets
.top();
2874 if ((eSrcCharSet
== RTL_TEXTENCODING_DONTKNOW
) && m_nCharFormat
>= 0 && o3tl::make_unsigned(m_nCharFormat
) < m_vColl
.size() )
2875 eSrcCharSet
= m_vColl
[m_nCharFormat
].GetCharSet();
2876 if ((eSrcCharSet
== RTL_TEXTENCODING_DONTKNOW
) && StyleExists(m_nCurrentColl
) && m_nCurrentColl
< m_vColl
.size())
2877 eSrcCharSet
= m_vColl
[m_nCurrentColl
].GetCharSet();
2878 if (eSrcCharSet
== RTL_TEXTENCODING_DONTKNOW
)
2879 eSrcCharSet
= GetCharSetFromLanguage();
2884 //Takashi Ono for CJK
2885 rtl_TextEncoding
SwWW8ImplReader::GetCurrentCJKCharSet()
2889 If the hard charset is set use it, if not see if there is an open
2890 character run that has set the charset, if not then fallback to the
2891 current underlying paragraph style.
2893 rtl_TextEncoding eSrcCharSet
= m_eHardCharSet
;
2894 if (eSrcCharSet
== RTL_TEXTENCODING_DONTKNOW
)
2896 if (!m_aFontSrcCJKCharSets
.empty())
2897 eSrcCharSet
= m_aFontSrcCJKCharSets
.top();
2898 if ((eSrcCharSet
== RTL_TEXTENCODING_DONTKNOW
) && m_nCharFormat
>= 0 && o3tl::make_unsigned(m_nCharFormat
) < m_vColl
.size() )
2899 eSrcCharSet
= m_vColl
[m_nCharFormat
].GetCJKCharSet();
2900 if (eSrcCharSet
== RTL_TEXTENCODING_DONTKNOW
&& StyleExists(m_nCurrentColl
) && m_nCurrentColl
< m_vColl
.size())
2901 eSrcCharSet
= m_vColl
[m_nCurrentColl
].GetCJKCharSet();
2902 if (eSrcCharSet
== RTL_TEXTENCODING_DONTKNOW
)
2903 eSrcCharSet
= GetCJKCharSetFromLanguage();
2908 void SwWW8ImplReader::PostProcessAttrs()
2910 if (m_pPostProcessAttrsInfo
== nullptr)
2913 SfxItemIter
aIter(m_pPostProcessAttrsInfo
->mItemSet
);
2915 for (const SfxPoolItem
* pItem
= aIter
.GetCurItem(); pItem
; pItem
= aIter
.NextItem())
2917 m_xCtrlStck
->NewAttr(*m_pPostProcessAttrsInfo
->mPaM
.GetPoint(),
2919 m_xCtrlStck
->SetAttr(*m_pPostProcessAttrsInfo
->mPaM
.GetMark(),
2923 m_pPostProcessAttrsInfo
.reset();
2928 It appears that some documents that are in a baltic 8 bit encoding which has
2929 some undefined characters can have use made of those characters, in which
2930 case they default to CP1252. If not then it's perhaps that the font encoding
2931 is only in use for 6/7 and for 8+ if we are in 8bit mode then the encoding
2934 So an encoding converter that on an undefined character attempts to
2935 convert from 1252 on the undefined character
2937 static std::size_t Custom8BitToUnicode(rtl_TextToUnicodeConverter hConverter
,
2938 char const *pIn
, std::size_t nInLen
, sal_Unicode
*pOut
, std::size_t nOutLen
)
2940 const sal_uInt32 nFlags
=
2941 RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
|
2942 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
|
2943 RTL_TEXTTOUNICODE_FLAGS_INVALID_IGNORE
|
2944 RTL_TEXTTOUNICODE_FLAGS_FLUSH
;
2946 const sal_uInt32 nFlags2
=
2947 RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_IGNORE
|
2948 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_IGNORE
|
2949 RTL_TEXTTOUNICODE_FLAGS_INVALID_IGNORE
|
2950 RTL_TEXTTOUNICODE_FLAGS_FLUSH
;
2952 std::size_t nDestChars
=0;
2953 std::size_t nConverted
=0;
2957 sal_uInt32 nInfo
= 0;
2958 sal_Size nThisConverted
=0;
2960 nDestChars
+= rtl_convertTextToUnicode(hConverter
, nullptr,
2961 pIn
+nConverted
, nInLen
-nConverted
,
2962 pOut
+nDestChars
, nOutLen
-nDestChars
,
2963 nFlags
, &nInfo
, &nThisConverted
);
2965 OSL_ENSURE(nInfo
== 0, "A character conversion failed!");
2967 nConverted
+= nThisConverted
;
2970 nInfo
& RTL_TEXTTOUNICODE_INFO_UNDEFINED
||
2971 nInfo
& RTL_TEXTTOUNICODE_INFO_MBUNDEFINED
2974 sal_Size nOtherConverted
;
2975 rtl_TextToUnicodeConverter hCP1252Converter
=
2976 rtl_createTextToUnicodeConverter(RTL_TEXTENCODING_MS_1252
);
2977 nDestChars
+= rtl_convertTextToUnicode(hCP1252Converter
, nullptr,
2979 pOut
+nDestChars
, nOutLen
-nDestChars
,
2980 nFlags2
, &nInfo
, &nOtherConverted
);
2981 rtl_destroyTextToUnicodeConverter(hCP1252Converter
);
2984 } while (nConverted
< nInLen
);
2989 bool SwWW8ImplReader::LangUsesHindiNumbers(LanguageType nLang
)
2991 bool bResult
= false;
2993 switch (static_cast<sal_uInt16
>(nLang
))
2995 case 0x1401: // Arabic(Algeria)
2996 case 0x3c01: // Arabic(Bahrain)
2997 case 0xc01: // Arabic(Egypt)
2998 case 0x801: // Arabic(Iraq)
2999 case 0x2c01: // Arabic (Jordan)
3000 case 0x3401: // Arabic(Kuwait)
3001 case 0x3001: // Arabic(Lebanon)
3002 case 0x1001: // Arabic(Libya)
3003 case 0x1801: // Arabic(Morocco)
3004 case 0x2001: // Arabic(Oman)
3005 case 0x4001: // Arabic(Qatar)
3006 case 0x401: // Arabic(Saudi Arabia)
3007 case 0x2801: // Arabic(Syria)
3008 case 0x1c01: // Arabic(Tunisia)
3009 case 0x3801: // Arabic(U.A.E)
3010 case 0x2401: // Arabic(Yemen)
3020 sal_Unicode
SwWW8ImplReader::TranslateToHindiNumbers(sal_Unicode nChar
)
3022 if (nChar
>= 0x0030 && nChar
<= 0x0039)
3023 return nChar
+ 0x0630;
3030 OUString
makeOUString(rtl_uString
*pStr
, sal_Int32 nAllocLen
)
3032 //if read len was in or around that of allocated len, just reuse pStr
3033 if (nAllocLen
< pStr
->length
+ 256)
3034 return OUString(pStr
, SAL_NO_ACQUIRE
);
3035 //otherwise copy the shorter used section to release extra mem
3036 OUString
sRet(pStr
->buffer
, pStr
->length
);
3037 rtl_uString_release(pStr
);
3043 * Return value: true for non special chars
3045 bool SwWW8ImplReader::ReadPlainChars(WW8_CP
& rPos
, sal_Int32 nEnd
, sal_Int32 nCpOfs
)
3047 sal_Int32 nRequestedStrLen
= nEnd
- rPos
;
3049 OSL_ENSURE(nRequestedStrLen
, "String is 0");
3050 if (nRequestedStrLen
<= 0)
3054 const bool bFail
= o3tl::checked_add(nCpOfs
, rPos
, nCp
);
3057 rPos
+=nRequestedStrLen
;
3061 sal_Int32 nRequestedPos
= m_xSBase
->WW8Cp2Fc(nCp
, &m_bIsUnicode
);
3062 bool bValidPos
= checkSeek(*m_pStrm
, nRequestedPos
);
3063 OSL_ENSURE(bValidPos
, "Document claimed to have more text than available");
3066 // Swallow missing range, e.g. #i95550#
3067 rPos
+=nRequestedStrLen
;
3071 std::size_t nAvailableStrLen
= m_pStrm
->remainingSize() / (m_bIsUnicode
? 2 : 1);
3072 OSL_ENSURE(nAvailableStrLen
, "Document claimed to have more text than available");
3073 if (!nAvailableStrLen
)
3075 // Swallow missing range, e.g. #i95550#
3076 rPos
+=nRequestedStrLen
;
3080 sal_Int32 nValidStrLen
= std::min
<std::size_t>(nRequestedStrLen
, nAvailableStrLen
);
3082 // Reset Unicode flag and correct FilePos if needed.
3083 // Note: Seek is not expensive, as we're checking inline whether or not
3084 // the correct FilePos has already been reached.
3085 const sal_Int32 nStrLen
= std::min(nValidStrLen
, SAL_MAX_INT32
-1);
3087 rtl_TextEncoding eSrcCharSet
= m_bVer67
? GetCurrentCharSet() :
3088 RTL_TEXTENCODING_MS_1252
;
3089 if (m_bVer67
&& eSrcCharSet
== RTL_TEXTENCODING_MS_932
)
3094 Older documents exported as word 95 that use unicode aware fonts will
3095 have the charset of those fonts set to RTL_TEXTENCODING_MS_932 on
3096 export as the conversion from RTL_TEXTENCODING_UNICODE. This is a serious
3099 We will try and use a fallback encoding if the conversion from
3100 RTL_TEXTENCODING_MS_932 fails, but you can get unlucky and get a document
3101 which isn't really in RTL_TEXTENCODING_MS_932 but parts of it form
3102 valid RTL_TEXTENCODING_MS_932 by chance :-(
3104 We're not the only ones that struggle with this: Here's the help from
3105 MSOffice 2003 on the topic:
3108 Earlier versions of Microsoft Word were sometimes used in conjunction with
3109 third-party language-processing add-in programs designed to support Chinese or
3110 Korean on English versions of Microsoft Windows. Use of these add-ins sometimes
3111 results in incorrect text display in more recent versions of Word.
3113 However, you can set options to convert these documents so that text is
3114 displayed correctly. On the Tools menu, click Options, and then click the
3115 General tab. In the English Word 6.0/95 documents list, select Contain Asian
3116 text (to have Word interpret the text as Asian code page data, regardless of
3117 its font) or Automatically detect Asian text (to have Word attempt to determine
3118 which parts of the text are meant to be Asian).
3121 What we can try here is to ignore a RTL_TEXTENCODING_MS_932 codepage if
3122 the language is not Japanese
3125 const SvxLanguageItem
* pItem
= GetFormatAttr(RES_CHRATR_CJK_LANGUAGE
);
3126 if (pItem
!= nullptr && LANGUAGE_JAPANESE
!= pItem
->GetLanguage())
3128 SAL_WARN("sw.ww8", "discarding word95 RTL_TEXTENCODING_MS_932 encoding");
3129 eSrcCharSet
= GetCharSetFromLanguage();
3132 const rtl_TextEncoding eSrcCJKCharSet
= m_bVer67
? GetCurrentCJKCharSet() :
3133 RTL_TEXTENCODING_MS_1252
;
3135 // allocate unicode string data
3136 auto l
= [](rtl_uString
* p
){rtl_uString_release(p
);};
3137 std::unique_ptr
<rtl_uString
, decltype(l
)> xStr(rtl_uString_alloc(nStrLen
), l
);
3138 sal_Unicode
* pBuffer
= xStr
->buffer
;
3139 sal_Unicode
* pWork
= pBuffer
;
3141 std::unique_ptr
<char[]> p8Bits
;
3143 rtl_TextToUnicodeConverter hConverter
= nullptr;
3144 if (!m_bIsUnicode
|| m_bVer67
)
3145 hConverter
= rtl_createTextToUnicodeConverter(eSrcCharSet
);
3148 p8Bits
.reset( new char[nStrLen
] );
3150 // read the stream data
3151 sal_uInt8 nBCode
= 0;
3154 LanguageType nCTLLang
= LANGUAGE_SYSTEM
;
3155 const SvxLanguageItem
* pItem
= GetFormatAttr(RES_CHRATR_CTL_LANGUAGE
);
3156 if (pItem
!= nullptr)
3157 nCTLLang
= pItem
->GetLanguage();
3160 for (nL2
= 0; nL2
< nStrLen
; ++nL2
)
3163 m_pStrm
->ReadUInt16( nUCode
); // unicode --> read 2 bytes
3166 m_pStrm
->ReadUChar( nBCode
); // old code --> read 1 byte
3170 if (!m_pStrm
->good())
3172 rPos
= WW8_CP_MAX
-10; // -> eof or other error
3176 if ((32 > nUCode
) || (0xa0 == nUCode
))
3178 m_pStrm
->SeekRel( m_bIsUnicode
? -2 : -1 );
3179 break; // Special character < 32, == 0xa0 found
3188 if (nUCode
>= 0x3000) //0x8000 ?
3191 aTest
[0] = static_cast< char >((nUCode
& 0xFF00) >> 8);
3192 aTest
[1] = static_cast< char >(nUCode
& 0x00FF);
3193 OUString
aTemp(aTest
, 2, eSrcCJKCharSet
);
3194 OSL_ENSURE(aTemp
.getLength() == 1, "so much for that theory");
3195 *pWork
++ = aTemp
[0];
3199 char cTest
= static_cast< char >(nUCode
& 0x00FF);
3200 pWork
+= Custom8BitToUnicode(hConverter
, &cTest
, 1, pWork
, 1);
3205 p8Bits
[nL2
] = nBCode
;
3210 const sal_Int32 nEndUsed
= !m_bIsUnicode
3211 ? Custom8BitToUnicode(hConverter
, p8Bits
.get(), nL2
, pBuffer
, nStrLen
)
3214 if (m_bRegardHindiDigits
&& m_bBidi
&& LangUsesHindiNumbers(nCTLLang
))
3216 for (sal_Int32 nI
= 0; nI
< nEndUsed
; ++nI
, ++pBuffer
)
3217 *pBuffer
= TranslateToHindiNumbers(*pBuffer
);
3220 xStr
->buffer
[nEndUsed
] = 0;
3221 xStr
->length
= nEndUsed
;
3223 emulateMSWordAddTextToParagraph(makeOUString(xStr
.release(), nStrLen
));
3225 if (!m_aApos
.back()) // a para end in apo doesn't count
3226 m_bWasParaEnd
= false; // No CR
3230 rtl_destroyTextToUnicodeConverter(hConverter
);
3231 return nL2
>= nStrLen
;
3234 #define MSASCII SAL_MAX_INT16
3238 // We want to force weak chars inside 0x0020 to 0x007F to LATIN
3239 sal_Int16
lcl_getScriptType(
3240 const uno::Reference
<i18n::XBreakIterator
>& rBI
,
3241 const OUString
&rString
, sal_Int32 nPos
)
3243 sal_Int16 nScript
= rBI
->getScriptType(rString
, nPos
);
3244 if (nScript
== i18n::ScriptType::WEAK
&& rString
[nPos
] >= 0x0020 && rString
[nPos
] <= 0x007F)
3249 // We want to know about WEAK segments, so endOfScript isn't
3250 // useful, and see lcl_getScriptType anyway
3251 sal_Int32
lcl_endOfScript(
3252 const uno::Reference
<i18n::XBreakIterator
>& rBI
,
3253 const OUString
&rString
, sal_Int32 nPos
, sal_Int16 nScript
)
3255 while (nPos
< rString
.getLength())
3257 sal_Int16 nNewScript
= lcl_getScriptType(rBI
, rString
, nPos
);
3258 if (nScript
!= nNewScript
)
3265 sal_Int32
lcl_getWriterScriptType(
3266 const uno::Reference
<i18n::XBreakIterator
>& rBI
,
3267 const OUString
&rString
, sal_Int32 nPos
)
3269 sal_Int16 nScript
= i18n::ScriptType::WEAK
;
3271 if (rString
.isEmpty())
3276 nScript
= rBI
->getScriptType(rString
, nPos
);
3277 if (nScript
!= i18n::ScriptType::WEAK
)
3285 bool samePitchIgnoreUnknown(FontPitch eA
, FontPitch eB
)
3287 return (eA
== eB
|| eA
== PITCH_DONTKNOW
|| eB
== PITCH_DONTKNOW
);
3290 bool sameFontIgnoringIrrelevantFields(const SvxFontItem
&rA
, const SvxFontItem
&rB
)
3292 // Ignoring CharSet, and ignoring unknown pitch
3293 return rA
.GetFamilyName() == rB
.GetFamilyName() &&
3294 rA
.GetStyleName() == rB
.GetStyleName() &&
3295 rA
.GetFamily() == rB
.GetFamily() &&
3296 samePitchIgnoreUnknown(rA
.GetPitch(), rB
.GetPitch());
3300 // In writer we categorize text into CJK, CTL and "Western" for everything else.
3301 // Microsoft Word basically categorizes text into East Asian, Complex, ASCII,
3302 // NonEastAsian/HighAnsi, with some shared characters and some properties to
3303 // hint as to which way to bias those shared characters.
3305 // That's four categories, we however have three categories. Given that problem
3306 // here we would ideally find out "what would word do" to see what font/language
3307 // word would assign to characters based on the unicode range they fall into and
3308 // hack the word one onto the range we use. However it's unclear what word's
3309 // categorization is. So we don't do that here yet.
3311 // Additional to the categorization, when word encounters weak text for ambiguous
3312 // chars it uses idcthint to indicate which way to bias. We don't have an idcthint
3313 // feature in writer.
3315 // So what we currently do here then is to split our text into non-weak/weak
3316 // sections and uses word's idcthint to determine what font it would use and
3317 // force that on for the segment. Following what we *do* know about word's
3318 // categorization, we know that the range 0x0020 and 0x007F is sprmCRgFtc0 in
3319 // word, something we map to LATIN, so we consider all weak chars in that range
3320 // to auto-bias to LATIN.
3322 // See https://bugs.libreoffice.org/show_bug.cgi?id=34319 for an example
3323 void SwWW8ImplReader::emulateMSWordAddTextToParagraph(const OUString
& rAddString
)
3325 if (rAddString
.isEmpty())
3330 simpleAddTextToParagraph(rAddString
);
3334 const uno::Reference
<i18n::XBreakIterator
>& xBI(g_pBreakIt
->GetBreakIter());
3337 sal_Int16 nScript
= lcl_getScriptType(xBI
, rAddString
, 0);
3338 sal_Int32 nLen
= rAddString
.getLength();
3340 OUString sParagraphText
;
3341 const SwContentNode
*pCntNd
= m_pPaM
->GetPointContentNode();
3342 const SwTextNode
* pNd
= pCntNd
? pCntNd
->GetTextNode() : nullptr;
3344 sParagraphText
= pNd
->GetText();
3345 sal_Int32 nParaOffset
= sParagraphText
.getLength();
3346 sParagraphText
= sParagraphText
+ rAddString
;
3351 sal_Int32 nEnd
= lcl_endOfScript(xBI
, rAddString
, nPos
, nScript
);
3355 OUString
sChunk(rAddString
.copy(nPos
, nEnd
-nPos
));
3356 const TypedWhichId
<SvxFontItem
> aIds
[] = {RES_CHRATR_FONT
, RES_CHRATR_CJK_FONT
, RES_CHRATR_CTL_FONT
};
3357 const SvxFontItem
*pOverriddenItems
[] = {nullptr, nullptr, nullptr};
3358 bool aForced
[] = {false, false, false};
3360 int nLclIdctHint
= 0xFF;
3361 if (nScript
== i18n::ScriptType::WEAK
)
3363 const SfxInt16Item
*pIdctHint
= GetFormatAttr(RES_CHRATR_IDCTHINT
);
3364 nLclIdctHint
= pIdctHint
->GetValue();
3366 else if (nScript
== MSASCII
) // Force weak chars in ascii range to use LATIN font
3369 TypedWhichId
<SvxFontItem
> nForceFromFontId(0);
3370 if (nLclIdctHint
!= 0xFF)
3372 switch (nLclIdctHint
)
3375 nForceFromFontId
= RES_CHRATR_FONT
;
3378 nForceFromFontId
= RES_CHRATR_CJK_FONT
;
3381 nForceFromFontId
= RES_CHRATR_CTL_FONT
;
3388 if (sal_uInt16(nForceFromFontId
) != 0)
3390 // Now we know that word would use the nForceFromFontId font for this range
3391 // Try and determine what script writer would assign this range to
3393 sal_Int32 nWriterScript
= lcl_getWriterScriptType(xBI
, sParagraphText
,
3394 nPos
+ nParaOffset
);
3396 bool bWriterWillUseSameFontAsWordAutomatically
= false;
3398 if (nWriterScript
!= i18n::ScriptType::WEAK
)
3401 (nWriterScript
== i18n::ScriptType::ASIAN
&& nForceFromFontId
== RES_CHRATR_CJK_FONT
) ||
3402 (nWriterScript
== i18n::ScriptType::COMPLEX
&& nForceFromFontId
== RES_CHRATR_CTL_FONT
) ||
3403 (nWriterScript
== i18n::ScriptType::LATIN
&& nForceFromFontId
== RES_CHRATR_FONT
)
3406 bWriterWillUseSameFontAsWordAutomatically
= true;
3410 const SvxFontItem
*pSourceFont
= GetFormatAttr(nForceFromFontId
);
3411 TypedWhichId
<SvxFontItem
> nDestId
= aIds
[nWriterScript
-1];
3412 const SvxFontItem
*pDestFont
= GetFormatAttr(nDestId
);
3413 bWriterWillUseSameFontAsWordAutomatically
= sameFontIgnoringIrrelevantFields(*pSourceFont
, *pDestFont
);
3417 // Writer won't use the same font as word, so force the issue
3418 if (!bWriterWillUseSameFontAsWordAutomatically
)
3420 const SvxFontItem
*pSourceFont
= GetFormatAttr(nForceFromFontId
);
3422 for (size_t i
= 0; i
< SAL_N_ELEMENTS(aIds
); ++i
)
3424 const SvxFontItem
*pDestFont
= GetFormatAttr(aIds
[i
]);
3425 aForced
[i
] = aIds
[i
] != nForceFromFontId
&& *pSourceFont
!= *pDestFont
;
3428 pOverriddenItems
[i
] =
3429 static_cast<const SvxFontItem
*>(m_xCtrlStck
->GetStackAttr(*m_pPaM
->GetPoint(), aIds
[i
]));
3431 SvxFontItem
aForceFont(*pSourceFont
);
3432 aForceFont
.SetWhich(aIds
[i
]);
3433 m_xCtrlStck
->NewAttr(*m_pPaM
->GetPoint(), aForceFont
);
3439 simpleAddTextToParagraph(sChunk
);
3441 for (size_t i
= 0; i
< SAL_N_ELEMENTS(aIds
); ++i
)
3445 m_xCtrlStck
->SetAttr(*m_pPaM
->GetPoint(), aIds
[i
]);
3446 if (pOverriddenItems
[i
])
3447 m_xCtrlStck
->NewAttr(*m_pPaM
->GetPoint(), *(pOverriddenItems
[i
]));
3453 nScript
= lcl_getScriptType(xBI
, rAddString
, nPos
);
3459 auto FilterControlChars(std::u16string_view aString
) -> OUString
3461 OUStringBuffer
buf(aString
.size());
3462 for (size_t i
= 0; i
< aString
.size(); ++i
)
3464 sal_Unicode
const ch(aString
[i
]);
3465 if (!linguistic::IsControlChar(ch
) || ch
== '\r' || ch
== '\n' || ch
== '\t')
3471 SAL_INFO("sw.ww8", "filtering control character");
3474 return buf
.makeStringAndClear();
3479 void SwWW8ImplReader::simpleAddTextToParagraph(std::u16string_view aAddString
)
3481 OUString
const addString(sw::FilterControlChars(aAddString
));
3483 if (addString
.isEmpty())
3486 const SwContentNode
*pCntNd
= m_pPaM
->GetPointContentNode();
3487 const SwTextNode
* pNd
= pCntNd
? pCntNd
->GetTextNode() : nullptr;
3489 OSL_ENSURE(pNd
, "What the hell, where's my text node");
3494 const sal_Int32 nCharsLeft
= SAL_MAX_INT32
- pNd
->GetText().getLength();
3497 if (addString
.getLength() <= nCharsLeft
)
3499 m_rDoc
.getIDocumentContentOperations().InsertString(*m_pPaM
, addString
);
3503 m_rDoc
.getIDocumentContentOperations().InsertString(*m_pPaM
, addString
.copy(0, nCharsLeft
));
3504 FinalizeTextNode(*m_pPaM
->GetPoint());
3505 m_rDoc
.getIDocumentContentOperations().InsertString(*m_pPaM
, addString
.copy(nCharsLeft
));
3510 FinalizeTextNode(*m_pPaM
->GetPoint());
3511 m_rDoc
.getIDocumentContentOperations().InsertString(*m_pPaM
, addString
);
3514 m_bReadTable
= false;
3518 * Return value: true for para end
3520 bool SwWW8ImplReader::ReadChars(WW8_CP
& rPos
, WW8_CP nNextAttr
, tools::Long nTextEnd
,
3523 tools::Long nEnd
= ( nNextAttr
< nTextEnd
) ? nNextAttr
: nTextEnd
;
3525 if (m_bSymbol
|| m_bIgnoreText
)
3527 WW8_CP nRequested
= nEnd
- rPos
;
3528 if (m_bSymbol
) // Insert special chars
3530 sal_uInt64 nMaxPossible
= m_pStrm
->remainingSize();
3531 if (o3tl::make_unsigned(nRequested
) > nMaxPossible
)
3533 SAL_WARN("sw.ww8", "document claims to have more characters, " << nRequested
<< " than remaining, " << nMaxPossible
);
3534 nRequested
= nMaxPossible
;
3537 if (!linguistic::IsControlChar(m_cSymbol
)
3538 || m_cSymbol
== '\r' || m_cSymbol
== '\n' || m_cSymbol
== '\t')
3540 for (WW8_CP nCh
= 0; nCh
< nRequested
; ++nCh
)
3542 m_rDoc
.getIDocumentContentOperations().InsertString(*m_pPaM
, OUString(m_cSymbol
));
3544 m_xCtrlStck
->SetAttr(*m_pPaM
->GetPoint(), RES_CHRATR_FONT
);
3545 m_xCtrlStck
->SetAttr(*m_pPaM
->GetPoint(), RES_CHRATR_CJK_FONT
);
3546 m_xCtrlStck
->SetAttr(*m_pPaM
->GetPoint(), RES_CHRATR_CTL_FONT
);
3549 m_pStrm
->SeekRel(nRequested
);
3550 rPos
= nEnd
; // Ignore until attribute end
3556 if (ReadPlainChars(rPos
, nEnd
, nCpOfs
))
3557 return false; // Done
3559 bool bStartLine
= ReadChar(rPos
, nCpOfs
);
3561 if (m_bPgSecBreak
|| bStartLine
|| rPos
== nEnd
) // CR or Done
3568 bool SwWW8ImplReader::HandlePageBreakChar()
3570 bool bParaEndAdded
= false;
3571 // #i1909# section/page breaks should not occur in tables, word
3572 // itself ignores them in this case.
3576 SwTextNode
* pTemp
= m_pPaM
->GetPointNode().GetTextNode();
3577 if (pTemp
&& pTemp
->GetText().isEmpty()
3578 && (m_bFirstPara
|| m_bFirstParaOfPage
))
3581 FinalizeTextNode(*m_pPaM
->GetPoint());
3582 pTemp
->SetAttr(*GetDfltAttr(RES_PARATR_NUMRULE
));
3585 m_bPgSecBreak
= true;
3586 m_xCtrlStck
->KillUnlockedAttrs(*m_pPaM
->GetPoint());
3588 If it's a 0x0c without a paragraph end before it, act like a
3589 paragraph end, but nevertheless, numbering (and perhaps other
3590 similar constructs) do not exist on the para.
3592 if (!m_bWasParaEnd
&& IsTemp
)
3594 bParaEndAdded
= true;
3595 if (0 >= m_pPaM
->GetPoint()->GetContentIndex())
3597 if (SwTextNode
* pTextNode
= m_pPaM
->GetPointNode().GetTextNode())
3600 *GetDfltAttr(RES_PARATR_NUMRULE
));
3605 return bParaEndAdded
;
3608 bool SwWW8ImplReader::ReadChar(tools::Long nPosCp
, tools::Long nCpOfs
)
3610 bool bNewParaEnd
= false;
3611 // Reset Unicode flag and correct FilePos if needed.
3612 // Note: Seek is not expensive, as we're checking inline whether or not
3613 // the correct FilePos has already been reached.
3614 std::size_t nRequestedPos
= m_xSBase
->WW8Cp2Fc(nCpOfs
+nPosCp
, &m_bIsUnicode
);
3615 if (!checkSeek(*m_pStrm
, nRequestedPos
))
3618 sal_uInt16
nWCharVal(0);
3620 m_pStrm
->ReadUInt16( nWCharVal
); // unicode --> read 2 bytes
3623 sal_uInt8
nBCode(0);
3624 m_pStrm
-> ReadUChar( nBCode
); // old code --> read 1 byte
3628 sal_Unicode cInsert
= '\x0';
3629 bool bParaMark
= false;
3631 if ( 0xc != nWCharVal
)
3632 m_bFirstParaOfPage
= false;
3640 SwPageNumberField
aField(
3641 static_cast<SwPageNumberFieldType
*>(m_rDoc
.getIDocumentFieldsAccess().GetSysFieldType(
3642 SwFieldIds::PageNumber
)), PG_RANDOM
, SVX_NUM_ARABIC
);
3643 m_rDoc
.getIDocumentContentOperations().InsertPoolItem(*m_pPaM
, SwFormatField(aField
));
3647 // extremely slow, so skip for fuzzing, and insert a space instead
3652 // if there is only one column word treats a column break like a pagebreak.
3653 if (m_aSectionManager
.CurrentSectionColCount() < 2)
3654 bParaMark
= HandlePageBreakChar();
3655 else if (!m_nInTable
)
3657 // Always insert a txtnode for a column break, e.g. ##
3658 SwContentNode
*pCntNd
=m_pPaM
->GetPointContentNode();
3659 if (pCntNd
!=nullptr && pCntNd
->Len()>0) // if par is empty not break is needed
3660 FinalizeTextNode(*m_pPaM
->GetPoint());
3661 m_rDoc
.getIDocumentContentOperations().InsertPoolItem(*m_pPaM
, SvxFormatBreakItem(SvxBreak::ColumnBefore
, RES_BREAK
));
3667 WW8PLCFxDesc
* pPap
= m_xPlcxMan
->GetPap();
3668 //The last paragraph of each cell is terminated by a special
3669 //paragraph mark called a cell mark. Following the cell mark
3670 //that ends the last cell of a table row, the table row is
3671 //terminated by a special paragraph mark called a row mark
3673 //So the 0x7 should be right at the end of the previous
3674 //range to be a real cell-end.
3675 if (pPap
->nOrigStartPos
== nPosCp
+1 ||
3676 pPap
->nOrigStartPos
== WW8_CP_MAX
)
3678 TabCellEnd(); // Table cell/row end
3685 if( !m_bSpec
) // "Satellite"
3686 cInsert
= u
'\x00a4';
3689 if( !m_bSpec
) // "Para End" char
3690 cInsert
= u
'\x00b5';
3691 //TODO: should this be U+00B6 PILCROW SIGN rather than
3692 // U+00B5 MICRO SIGN?
3695 if( !m_bSpec
) // Juristenparagraph
3697 cp_set::iterator aItr
= m_aTOXEndCps
.find(static_cast<WW8_CP
>(nPosCp
));
3698 if (aItr
== m_aTOXEndCps
.end())
3699 cInsert
= u
'\x00a7';
3701 m_aTOXEndCps
.erase(aItr
);
3705 cInsert
= '\x9'; // Tab
3708 cInsert
= '\xa'; // Hard NewLine
3711 bParaMark
= HandlePageBreakChar();
3713 case 0x1e: // Non-breaking hyphen
3714 m_rDoc
.getIDocumentContentOperations().InsertString( *m_pPaM
, OUString(CHAR_HARDHYPHEN
) );
3716 case 0x1f: // Non-required hyphens
3717 m_rDoc
.getIDocumentContentOperations().InsertString( *m_pPaM
, OUString(CHAR_SOFTHYPHEN
) );
3719 case 0xa0: // Non-breaking spaces
3720 m_rDoc
.getIDocumentContentOperations().InsertString( *m_pPaM
, OUString(CHAR_HARDBLANK
) );
3724 Current thinking is that if bObj is set then we have a
3725 straightforward "traditional" ole object, otherwise we have a
3726 graphic preview of an associated ole2 object (or a simple
3729 normally in the canvas field, the code is 0x8 0x1.
3730 in a special case, the code is 0x1 0x1, which yields a simple picture
3733 bool bReadObj
= IsInlineEscherHack();
3736 sal_uInt64 nCurPos
= m_pStrm
->Tell();
3737 sal_uInt16
nWordCode(0);
3740 m_pStrm
->ReadUInt16( nWordCode
);
3743 sal_uInt8
nByteCode(0);
3744 m_pStrm
->ReadUChar( nByteCode
);
3745 nWordCode
= nByteCode
;
3747 if( nWordCode
== 0x1 )
3749 m_pStrm
->Seek( nCurPos
);
3753 SwFrameFormat
*pResult
= nullptr;
3755 pResult
= ImportOle();
3758 SwFrameFormat
* pAsCharFlyFormat
=
3759 m_rDoc
.MakeFrameFormat(OUString(), m_rDoc
.GetDfltFrameFormat(), true);
3760 SwFormatAnchor
aAnchor(RndStdIds::FLY_AS_CHAR
);
3761 pAsCharFlyFormat
->SetFormatAttr(aAnchor
);
3762 pResult
= ImportGraf(nullptr, pAsCharFlyFormat
);
3763 m_rDoc
.DelFrameFormat(pAsCharFlyFormat
);
3767 // If we have a bad 0x1 insert a space instead.
3771 OSL_ENSURE(!m_bObj
&& !m_bEmbeddObj
&& !m_nObjLocFc
,
3772 "WW8: Please report this document, it may have a "
3778 m_bObj
= m_bEmbeddObj
= false;
3786 Read_GrafLayer( nPosCp
);
3789 bNewParaEnd
= bParaMark
= true;
3794 Yes complex, if there is an entry in the undocumented PLCF
3795 which I believe to be a record of cell and row boundaries
3796 see if the magic bit which I believe to mean cell end is
3797 set. I also think btw that the third byte of the 4 byte
3798 value is the level of the cell
3800 WW8PLCFspecial
* pTest
= m_xPlcxMan
->GetMagicTables();
3801 if (pTest
&& pTest
->SeekPosExact(nPosCp
+1+nCpOfs
) &&
3802 pTest
->Where() == nPosCp
+1+nCpOfs
)
3806 sal_uInt32 nData
= pTest
->Get(nPos
, pData
) ? SVBT32ToUInt32(*static_cast<SVBT32
*>(pData
))
3808 if (nData
& 0x2) // Might be how it works
3814 // tdf#106799: We expect TTP marks to be also cell marks,
3815 // but sometimes sprmPFInnerTtp comes without sprmPFInnerTableCell
3816 else if (m_bWasTabCellEnd
|| m_bWasTabRowEnd
)
3823 m_bWasTabCellEnd
= false;
3826 case 0x5: // Annotation reference
3829 case 0x2: // TODO: Auto-Footnote-Number, should be replaced by SwWW8ImplReader::End_Footnote later
3830 if (!m_aFootnoteStack
.empty())
3834 SAL_INFO( "sw.ww8.level2", "<unknownValue val=\"" << nWCharVal
<< "\">" );
3838 if( '\x0' != cInsert
)
3840 OUString
sInsert(cInsert
);
3841 emulateMSWordAddTextToParagraph(sInsert
);
3843 if (!m_aApos
.back()) // a para end in apo doesn't count
3844 m_bWasParaEnd
= bNewParaEnd
;
3848 void SwWW8ImplReader::ProcessCurrentCollChange(WW8PLCFManResult
& rRes
,
3849 bool* pStartAttr
, bool bCallProcessSpecial
)
3851 sal_uInt16 nOldColl
= m_nCurrentColl
;
3852 m_nCurrentColl
= m_xPlcxMan
->GetColl();
3855 if (m_nCurrentColl
>= m_vColl
.size() || !m_vColl
[m_nCurrentColl
].m_pFormat
|| !m_vColl
[m_nCurrentColl
].m_bColl
)
3858 m_bParaAutoBefore
= false;
3859 m_bParaAutoAfter
= false;
3863 m_bParaAutoBefore
= m_vColl
[m_nCurrentColl
].m_bParaAutoBefore
;
3864 m_bParaAutoAfter
= m_vColl
[m_nCurrentColl
].m_bParaAutoAfter
;
3867 if (nOldColl
>= m_vColl
.size())
3868 nOldColl
= 0; // guess! TODO make sure this is what we want
3870 bool bTabRowEnd
= false;
3871 if( pStartAttr
&& bCallProcessSpecial
&& !m_bInHyperlink
)
3874 // Frame/Table/Autonumbering List Level
3875 bTabRowEnd
= ProcessSpecial(bReSync
, rRes
.nCurrentCp
+ m_xPlcxMan
->GetCpOfs());
3877 *pStartAttr
= m_xPlcxMan
->Get( &rRes
); // Get Attribute-Pos again
3880 if (!bTabRowEnd
&& StyleExists(m_nCurrentColl
))
3882 SetTextFormatCollAndListLevel( *m_pPaM
, m_vColl
[ m_nCurrentColl
]);
3883 ChkToggleAttr(m_vColl
[ nOldColl
].m_n81Flags
, m_vColl
[ m_nCurrentColl
].m_n81Flags
);
3884 ChkToggleBiDiAttr(m_vColl
[nOldColl
].m_n81BiDiFlags
,
3885 m_vColl
[m_nCurrentColl
].m_n81BiDiFlags
);
3889 tools::Long
SwWW8ImplReader::ReadTextAttr(WW8_CP
& rTextPos
, tools::Long nTextEnd
, bool& rbStartLine
, int nDepthGuard
)
3891 tools::Long nSkipChars
= 0;
3892 WW8PLCFManResult aRes
;
3894 OSL_ENSURE(m_pPaM
->GetPointNode().GetTextNode(), "Missing txtnode");
3895 bool bStartAttr
= m_xPlcxMan
->Get(&aRes
); // Get Attribute position again
3896 aRes
.nCurrentCp
= rTextPos
; // Current Cp position
3898 bool bNewSection
= (aRes
.nFlags
& MAN_MASK_NEW_SEP
) && !m_bIgnoreText
;
3899 if ( bNewSection
) // New Section
3901 OSL_ENSURE(m_pPaM
->GetPointNode().GetTextNode(), "Missing txtnode");
3902 // Create PageDesc and fill it
3903 m_aSectionManager
.CreateSep(rTextPos
);
3904 // -> 0xc was a Sectionbreak, but not a Pagebreak;
3905 // Create PageDesc and fill it
3906 m_bPgSecBreak
= false;
3907 OSL_ENSURE(m_pPaM
->GetPointNode().GetTextNode(), "Missing txtnode");
3910 // New paragraph over Plcx.Fkp.papx
3911 if ( (aRes
.nFlags
& MAN_MASK_NEW_PAP
)|| rbStartLine
)
3913 ProcessCurrentCollChange( aRes
, &bStartAttr
,
3914 MAN_MASK_NEW_PAP
== (aRes
.nFlags
& MAN_MASK_NEW_PAP
) &&
3916 rbStartLine
= false;
3919 // position of last CP that's to be ignored
3920 tools::Long nSkipPos
= -1;
3922 if( 0 < aRes
.nSprmId
) // Ignore empty Attrs
3924 if( ( eFTN
> aRes
.nSprmId
) || ( 0x0800 <= aRes
.nSprmId
) )
3926 if( bStartAttr
) // WW attributes
3928 if( aRes
.nMemLen
>= 0 )
3929 ImportSprm(aRes
.pMemPos
, aRes
.nMemLen
, aRes
.nSprmId
);
3932 EndSprm( aRes
.nSprmId
); // Switch off Attr
3934 else if( aRes
.nSprmId
< 0x800 ) // Own helper attributes
3938 nSkipChars
= ImportExtSprm(&aRes
);
3940 (aRes
.nSprmId
== eFTN
) || (aRes
.nSprmId
== eEDN
) ||
3941 (aRes
.nSprmId
== eFLD
) || (aRes
.nSprmId
== eAND
)
3944 WW8_CP nMaxLegalSkip
= nTextEnd
- rTextPos
;
3945 // Skip Field/Footnote-/End-Note here
3946 rTextPos
+= std::min
<WW8_CP
>(nSkipChars
, nMaxLegalSkip
);
3947 nSkipPos
= rTextPos
-1;
3951 EndExtSprm( aRes
.nSprmId
);
3955 sal_Int32 nRequestedPos
= m_xSBase
->WW8Cp2Fc(m_xPlcxMan
->GetCpOfs() + rTextPos
, &m_bIsUnicode
);
3956 bool bValidPos
= checkSeek(*m_pStrm
, nRequestedPos
);
3957 SAL_WARN_IF(!bValidPos
, "sw.ww8", "Document claimed to have text at an invalid position, skip attributes for region");
3959 // Find next Attr position (and Skip attributes of field contents if needed)
3960 if (nSkipChars
&& !m_bIgnoreText
)
3961 m_xCtrlStck
->MarkAllAttrsOld();
3962 bool bOldIgnoreText
= m_bIgnoreText
;
3963 m_bIgnoreText
= true;
3964 sal_uInt16 nOldColl
= m_nCurrentColl
;
3965 bool bDoPlcxManPlusPLus
= true;
3969 if( bDoPlcxManPlusPLus
)
3970 m_xPlcxMan
->advance();
3971 nNext
= bValidPos
? m_xPlcxMan
->Where() : nTextEnd
;
3973 if (m_pPostProcessAttrsInfo
&&
3974 m_pPostProcessAttrsInfo
->mnCpStart
== nNext
)
3976 m_pPostProcessAttrsInfo
->mbCopy
= true;
3979 if( (0 <= nNext
) && (nSkipPos
>= nNext
) )
3981 if (nDepthGuard
>= 1024)
3983 SAL_WARN("sw.ww8", "ReadTextAttr hit recursion limit");
3987 nNext
= ReadTextAttr(rTextPos
, nTextEnd
, rbStartLine
, nDepthGuard
+ 1);
3988 bDoPlcxManPlusPLus
= false;
3989 m_bIgnoreText
= true;
3992 if (m_pPostProcessAttrsInfo
&&
3993 nNext
> m_pPostProcessAttrsInfo
->mnCpEnd
)
3995 m_pPostProcessAttrsInfo
->mbCopy
= false;
3998 while( nSkipPos
>= nNext
);
3999 m_bIgnoreText
= bOldIgnoreText
;
4002 m_xCtrlStck
->KillUnlockedAttrs( *m_pPaM
->GetPoint() );
4003 if( nOldColl
!= m_xPlcxMan
->GetColl() )
4004 ProcessCurrentCollChange(aRes
, nullptr, false);
4010 void SwWW8ImplReader::ReadAttrs(WW8_CP
& rTextPos
, WW8_CP
& rNext
, tools::Long nTextEnd
, bool& rbStartLine
)
4012 // Do we have attributes?
4013 if( rTextPos
>= rNext
)
4017 rNext
= ReadTextAttr(rTextPos
, nTextEnd
, rbStartLine
);
4018 if (rTextPos
== rNext
&& rTextPos
>= nTextEnd
)
4021 while( rTextPos
>= rNext
);
4024 else if ( rbStartLine
)
4026 /* No attributes, but still a new line.
4027 * If a line ends with a line break and paragraph attributes or paragraph templates
4028 * do NOT change the line end was not added to the Plcx.Fkp.papx i.e. (nFlags & MAN_MASK_NEW_PAP)
4030 * Due to this we need to set the template here as a kind of special treatment.
4032 if (!m_bCpxStyle
&& m_nCurrentColl
< m_vColl
.size())
4033 SetTextFormatCollAndListLevel(*m_pPaM
, m_vColl
[m_nCurrentColl
]);
4034 rbStartLine
= false;
4039 * CloseAttrEnds to only read the attribute ends at the end of a text or a
4040 * text area (Header, Footnote, ...).
4041 * We ignore attribute starts and fields.
4043 void SwWW8ImplReader::CloseAttrEnds()
4045 // If there are any unclosed sprms then copy them to
4046 // another stack and close the ones that must be closed
4047 std::stack
<sal_uInt16
> aStack
;
4048 m_xPlcxMan
->TransferOpenSprms(aStack
);
4050 while (!aStack
.empty())
4052 sal_uInt16 nSprmId
= aStack
.top();
4053 if ((0 < nSprmId
) && (( eFTN
> nSprmId
) || (0x0800 <= nSprmId
)))
4061 bool SwWW8ImplReader::ReadText(WW8_CP nStartCp
, WW8_CP nTextLen
, ManTypes nType
)
4065 bool bStartLine
= true;
4067 short nDistance
= 0;
4069 m_bWasParaEnd
= false;
4071 m_xCurrentItemSet
.reset();
4074 m_bPgSecBreak
= false;
4076 m_xPlcxMan
= std::make_shared
<WW8PLCFMan
>(m_xSBase
.get(), nType
, nStartCp
);
4077 tools::Long nCpOfs
= m_xPlcxMan
->GetCpOfs(); // Offset for Header/Footer, Footnote
4079 WW8_CP nNext
= m_xPlcxMan
->Where();
4080 m_xPreviousNode
.reset();
4081 sal_uInt8 nDropLines
= 0;
4082 SwCharFormat
* pNewSwCharFormat
= nullptr;
4083 const SwCharFormat
* pFormat
= nullptr;
4085 bool bValidPos
= checkSeek(*m_pStrm
, m_xSBase
->WW8Cp2Fc(nStartCp
+ nCpOfs
, &m_bIsUnicode
));
4089 WW8_CP l
= nStartCp
;
4090 const WW8_CP nMaxPossible
= WW8_CP_MAX
-nStartCp
;
4091 if (nTextLen
> nMaxPossible
)
4093 SAL_WARN_IF(nTextLen
> nMaxPossible
, "sw.ww8", "TextLen too long");
4094 nTextLen
= nMaxPossible
;
4096 WW8_CP nTextEnd
= nStartCp
+nTextLen
;
4097 while (l
< nTextEnd
)
4099 ReadAttrs( l
, nNext
, nTextEnd
, bStartLine
);// Takes SectionBreaks into account, too
4100 OSL_ENSURE(m_pPaM
->GetPointNode().GetTextNode(), "Missing txtnode");
4102 if (m_pPostProcessAttrsInfo
!= nullptr)
4108 bStartLine
= ReadChars(l
, nNext
, nTextEnd
, nCpOfs
);
4110 // If the previous paragraph was a dropcap then do not
4111 // create a new txtnode and join the two paragraphs together
4112 if (bStartLine
&& !m_xPreviousNode
) // Line end
4115 if (m_bCareFirstParaEndInToc
)
4117 m_bCareFirstParaEndInToc
= false;
4118 if (m_pPaM
->End() && m_pPaM
->End()->GetNode().GetTextNode() && m_pPaM
->End()->GetNode().GetTextNode()->Len() == 0)
4121 if (m_bCareLastParaEndInToc
)
4123 m_bCareLastParaEndInToc
= false;
4124 if (m_pPaM
->End() && m_pPaM
->End()->GetNode().GetTextNode() && m_pPaM
->End()->GetNode().GetTextNode()->Len() == 0)
4129 FinalizeTextNode(*m_pPaM
->GetPoint());
4133 if (SwTextNode
* pPreviousNode
= (bStartLine
&& m_xPreviousNode
) ? m_xPreviousNode
->GetTextNode() : nullptr)
4135 SwTextNode
* pEndNd
= m_pPaM
->GetPointNode().GetTextNode();
4136 SAL_WARN_IF(!pEndNd
, "sw.ww8", "didn't find textnode for dropcap");
4139 const sal_Int32 nDropCapLen
= pPreviousNode
->GetText().getLength();
4141 // Need to reset the font size and text position for the dropcap
4143 SwPaM
aTmp(*pEndNd
, 0, *pEndNd
, nDropCapLen
+1);
4144 m_xCtrlStck
->Delete(aTmp
);
4147 // Get the default document dropcap which we can use as our template
4148 const SwFormatDrop
* defaultDrop
= GetFormatAttr(RES_PARATR_DROP
);
4149 SwFormatDrop
aDrop(*defaultDrop
);
4151 aDrop
.SetLines(nDropLines
);
4152 aDrop
.SetDistance(nDistance
);
4153 aDrop
.SetChars(writer_cast
<sal_uInt8
>(nDropCapLen
));
4154 // Word has no concept of a "whole word dropcap"
4155 aDrop
.SetWholeWord(false);
4158 aDrop
.SetCharFormat(const_cast<SwCharFormat
*>(pFormat
));
4159 else if(pNewSwCharFormat
)
4160 aDrop
.SetCharFormat(pNewSwCharFormat
);
4162 SwPosition
aStart(*pEndNd
);
4163 m_xCtrlStck
->NewAttr(aStart
, aDrop
);
4164 m_xCtrlStck
->SetAttr(*m_pPaM
->GetPoint(), RES_PARATR_DROP
);
4166 m_xPreviousNode
.reset();
4168 else if (m_bDropCap
)
4170 // If we have found a dropcap store the textnode
4171 m_xPreviousNode
.reset(new TextNodeListener(m_pPaM
->GetPointNode().GetTextNode()));
4175 aDCS
= m_xPlcxMan
->GetPapPLCF()->HasSprm(46);
4177 aDCS
= m_xPlcxMan
->GetPapPLCF()->HasSprm(0x442C);
4179 if (aDCS
.pSprm
&& aDCS
.nRemainingData
>= 1)
4180 nDropLines
= (*aDCS
.pSprm
) >> 3;
4181 else // There is no Drop Cap Specifier hence no dropcap
4182 m_xPreviousNode
.reset();
4184 SprmResult aDistance
= m_xPlcxMan
->GetPapPLCF()->HasSprm(0x842F);
4185 if (aDistance
.pSprm
&& aDistance
.nRemainingData
>= 2)
4186 nDistance
= SVBT16ToUInt16(aDistance
.pSprm
);
4190 const SwFormatCharFormat
*pSwFormatCharFormat
= nullptr;
4192 if (m_xCurrentItemSet
)
4193 pSwFormatCharFormat
= &(m_xCurrentItemSet
->Get(RES_TXTATR_CHARFMT
));
4195 if (pSwFormatCharFormat
)
4196 pFormat
= pSwFormatCharFormat
->GetCharFormat();
4198 if (m_xCurrentItemSet
&& !pFormat
)
4200 OUString sPrefix
= "WW8Dropcap" + OUString::number(m_nDropCap
++);
4201 pNewSwCharFormat
= m_rDoc
.MakeCharFormat(sPrefix
, m_rDoc
.GetDfltCharFormat());
4202 m_xCurrentItemSet
->ClearItem(RES_CHRATR_ESCAPEMENT
);
4203 pNewSwCharFormat
->SetFormatAttr(*m_xCurrentItemSet
);
4206 m_xCurrentItemSet
.reset();
4210 if (bStartLine
|| m_bWasTabRowEnd
)
4212 // Call all 64 CRs; not for Header and the like
4213 if ((nCrCount
++ & 0x40) == 0 && nType
== MAN_MAINTEXT
&& l
<= nTextLen
)
4215 if (nTextLen
< WW8_CP_MAX
/100)
4216 m_nProgress
= o3tl::narrowing
<sal_uInt16
>(l
* 100 / nTextLen
);
4218 m_nProgress
= o3tl::narrowing
<sal_uInt16
>(l
/ nTextLen
* 100);
4219 m_xProgress
->Update(m_nProgress
); // Update
4223 // If we have encountered a 0x0c which indicates either section of
4224 // pagebreak then look it up to see if it is a section break, and
4225 // if it is not then insert a page break. If it is a section break
4226 // it will be handled as such in the ReadAttrs of the next loop
4229 // We need only to see if a section is ending at this cp,
4230 // the plcf will already be sitting on the correct location
4233 aTemp
.nStartPos
= aTemp
.nEndPos
= WW8_CP_MAX
;
4234 if (m_xPlcxMan
->GetSepPLCF())
4235 m_xPlcxMan
->GetSepPLCF()->GetSprms(&aTemp
);
4236 if ((aTemp
.nStartPos
!= l
) && (aTemp
.nEndPos
!= l
))
4238 // #i39251# - insert text node for page break, if no one inserted.
4239 // #i43118# - refine condition: the anchor
4240 // control stack has to have entries, otherwise it's not needed
4241 // to insert a text node.
4242 if (!bStartLine
&& !m_xAnchorStck
->empty())
4244 FinalizeTextNode(*m_pPaM
->GetPoint());
4246 m_rDoc
.getIDocumentContentOperations().InsertPoolItem(*m_pPaM
,
4247 SvxFormatBreakItem(SvxBreak::PageBefore
, RES_BREAK
));
4248 m_bFirstParaOfPage
= true;
4249 m_bPgSecBreak
= false;
4254 m_xPreviousNode
.reset();
4256 if (m_pPaM
->GetPoint()->GetContentIndex())
4257 FinalizeTextNode(*m_pPaM
->GetPoint());
4259 if (!m_bInHyperlink
)
4260 bJoined
= JoinNode(*m_pPaM
);
4268 SwWW8ImplReader::SwWW8ImplReader(sal_uInt8 nVersionPara
, SotStorage
* pStorage
,
4269 SvStream
* pSt
, SwDoc
& rD
, OUString aBaseURL
, bool bNewDoc
, bool bSkipImages
, SwPosition
const &rPos
)
4270 : m_pDocShell(rD
.GetDocShell())
4273 , m_pTableStream(nullptr)
4274 , m_pDataStream(nullptr)
4277 , m_aSectionManager(*this)
4278 , m_aExtraneousParas(rD
)
4279 , m_aInsertedTables(rD
)
4280 , m_aSectionNameGenerator(rD
, u
"WW"_ustr
)
4281 , m_aGrfNameGenerator(bNewDoc
, OUString('G'))
4282 , m_aParaStyleMapper(rD
)
4283 , m_aCharStyleMapper(rD
)
4284 , m_pFlyFormatOfJustInsertedGraphic(nullptr)
4285 , m_pPreviousNumPaM(nullptr)
4286 , m_pPrevNumRule(nullptr)
4287 , m_pCurrentColl(nullptr)
4288 , m_pDfltTextFormatColl(nullptr)
4289 , m_pStandardFormatColl(nullptr)
4290 , m_pDrawModel(nullptr)
4291 , m_pDrawPg(nullptr)
4292 , m_pNumFieldType(nullptr)
4293 , m_sBaseURL(std::move(aBaseURL
))
4297 , m_bRegardHindiDigits( false )
4298 , m_bDrawCpOValid( false )
4304 , m_eTextCharSet(RTL_TEXTENCODING_ASCII_US
)
4305 , m_eStructCharSet(RTL_TEXTENCODING_ASCII_US
)
4306 , m_eHardCharSet(RTL_TEXTENCODING_DONTKNOW
)
4310 , m_nLFOPosition(USHRT_MAX
)
4317 , m_nWantedVersion(nVersionPara
)
4318 , m_nSwNumLevel(0xff)
4319 , m_nWwNumType(0xff)
4320 , m_pChosenWW8OutlineStyle(nullptr)
4321 , m_nListLevel(MAXLEVEL
)
4322 , m_bNewDoc(bNewDoc
)
4323 , m_bSkipImages(bSkipImages
)
4324 , m_bReadNoTable(false)
4325 , m_bPgSecBreak(false)
4328 , m_bTxbxFlySection(false)
4329 , m_bHasBorder(false)
4331 , m_bIgnoreText(false)
4333 , m_bWasTabRowEnd(false)
4334 , m_bWasTabCellEnd(false)
4336 , m_bHdFtFootnoteEdn(false)
4337 , m_bFootnoteEdn(false)
4338 , m_bIsHeader(false)
4339 , m_bIsFooter(false)
4340 , m_bIsUnicode(false)
4341 , m_bCpxStyle(false)
4342 , m_bStyNormal(false)
4343 , m_bWWBugNormal(false)
4344 , m_bNoAttrImport(false)
4345 , m_bInHyperlink(false)
4346 , m_bWasParaEnd(false)
4351 , m_bEmbeddObj(false)
4352 , m_bCurrentAND_fNumberAcross(false)
4353 , m_bNoLnNumYet(true)
4354 , m_bFirstPara(true)
4355 , m_bFirstParaOfPage(false)
4356 , m_bParaAutoBefore(false)
4357 , m_bParaAutoAfter(false)
4361 , m_bReadTable(false)
4362 , m_bLoadingTOXCache(false)
4363 , m_nEmbeddedTOXLevel(0)
4364 , m_bLoadingTOXHyperlink(false)
4365 , m_bCareFirstParaEndInToc(false)
4366 , m_bCareLastParaEndInToc(false)
4367 , m_bNotifyMacroEventRead(false)
4368 , m_bFuzzing(comphelper::IsFuzzing())
4370 m_pStrm
->SetEndian( SvStreamEndian::LITTLE
);
4371 m_aApos
.push_back(false);
4373 mpCursor
= m_rDoc
.CreateUnoCursor(rPos
);
4376 SwWW8ImplReader::~SwWW8ImplReader()
4380 void SwWW8ImplReader::DeleteStack(std::unique_ptr
<SwFltControlStack
> pStck
)
4384 pStck
->SetAttr( *m_pPaM
->GetPoint(), 0, false);
4385 pStck
->SetAttr( *m_pPaM
->GetPoint(), 0, false);
4389 OSL_ENSURE( false, "WW stack already deleted" );
4393 void wwSectionManager::SetSegmentToPageDesc(const wwSection
&rSection
,
4396 SwPageDesc
&rPage
= *rSection
.mpPage
;
4398 SetNumberingType(rSection
, rPage
);
4400 SwFrameFormat
&rFormat
= rPage
.GetMaster();
4402 if(mrReader
.m_xWDop
->fUseBackGroundInAllmodes
) // #i56806# Make sure mrReader is initialized
4403 mrReader
.GraphicCtor();
4405 if (mrReader
.m_xWDop
->fUseBackGroundInAllmodes
&& mrReader
.m_xMSDffManager
)
4407 tools::Rectangle
aRect(0, 0, 100, 100); // A dummy, we don't care about the size
4408 SvxMSDffImportData
aData(aRect
);
4409 rtl::Reference
<SdrObject
> pObject
;
4410 if (mrReader
.m_xMSDffManager
->GetShape(0x401, pObject
, aData
) && !aData
.empty())
4412 // Only handle shape if it is a background shape
4413 if (aData
.begin()->get()->nFlags
& ShapeFlag::Background
)
4415 SfxItemSetFixed
<RES_BACKGROUND
, RES_BACKGROUND
,XATTR_START
, XATTR_END
>
4416 aSet(rFormat
.GetDoc()->GetAttrPool());
4417 mrReader
.MatchSdrItemsIntoFlySet(pObject
.get(), aSet
, mso_lineSimple
,
4418 mso_lineSolid
, mso_sptRectangle
, aRect
);
4419 if ( aSet
.HasItem(RES_BACKGROUND
) )
4420 rFormat
.SetFormatAttr(aSet
.Get(RES_BACKGROUND
));
4422 rFormat
.SetFormatAttr(aSet
);
4426 wwULSpaceData aULData
;
4427 GetPageULData(rSection
, aULData
);
4428 SetPageULSpaceItems(rFormat
, aULData
, rSection
);
4430 rPage
.SetVerticalAdjustment( rSection
.mnVerticalAdjustment
);
4432 SetPage(rPage
, rFormat
, rSection
, bIgnoreCols
);
4434 if (!(rSection
.maSep
.pgbApplyTo
& 1))
4435 SwWW8ImplReader::SetPageBorder(rFormat
, rSection
);
4436 if (!(rSection
.maSep
.pgbApplyTo
& 2))
4437 SwWW8ImplReader::SetPageBorder(rPage
.GetFirstMaster(), rSection
);
4439 mrReader
.SetDocumentGrid(rFormat
, rSection
);
4442 void wwSectionManager::SetUseOn(wwSection
&rSection
)
4444 bool bMirror
= mrReader
.m_xWDop
->fMirrorMargins
||
4445 mrReader
.m_xWDop
->doptypography
.m_f2on1
;
4447 UseOnPage eUseBase
= bMirror
? UseOnPage::Mirror
: UseOnPage::All
;
4448 UseOnPage eUse
= eUseBase
;
4449 if (!mrReader
.m_xWDop
->fFacingPages
)
4450 eUse
|= UseOnPage::HeaderShare
| UseOnPage::FooterShare
;
4451 if (!rSection
.HasTitlePage())
4452 eUse
|= UseOnPage::FirstShare
;
4454 OSL_ENSURE(rSection
.mpPage
, "Makes no sense to call me with no pages to set");
4455 if (rSection
.mpPage
)
4456 rSection
.mpPage
->WriteUseOn(eUse
);
4460 * Set the page descriptor on this node, handle the different cases for a text
4463 static void GiveNodePageDesc(SwNodeIndex
const &rIdx
, const SwFormatPageDesc
&rPgDesc
,
4467 If it's a table here, apply the pagebreak to the table
4468 properties, otherwise we add it to the para at this
4471 if (rIdx
.GetNode().IsTableNode())
4474 rIdx
.GetNode().GetTableNode()->GetTable();
4475 SwFrameFormat
* pApply
= rTable
.GetFrameFormat();
4476 OSL_ENSURE(pApply
, "impossible");
4478 pApply
->SetFormatAttr(rPgDesc
);
4483 rDoc
.getIDocumentContentOperations().InsertPoolItem(aPage
, rPgDesc
);
4488 * Map a word section to a writer page descriptor
4490 SwFormatPageDesc
wwSectionManager::SetSwFormatPageDesc(mySegIter
const &rIter
,
4491 mySegIter
const &rStart
, bool bIgnoreCols
)
4493 if (mrReader
.m_bNewDoc
&& rIter
== rStart
)
4496 mrReader
.m_rDoc
.getIDocumentStylePoolAccess().GetPageDescFromPool(RES_POOLPAGE_STANDARD
);
4500 rIter
->mpPage
= mrReader
.m_rDoc
.MakePageDesc(
4501 SwViewShell::GetShellRes()->GetPageDescName(mnDesc
, ShellResource::NORMAL_PAGE
),
4504 OSL_ENSURE(rIter
->mpPage
, "no page!");
4506 return SwFormatPageDesc();
4508 // Set page before hd/ft
4509 const wwSection
*pPrevious
= nullptr;
4510 if (rIter
!= rStart
)
4511 pPrevious
= &(*(rIter
-1));
4512 SetHdFt(*rIter
, std::distance(rStart
, rIter
), pPrevious
);
4515 // Set hd/ft after set page
4516 SetSegmentToPageDesc(*rIter
, bIgnoreCols
);
4518 SwFormatPageDesc
aRet(rIter
->mpPage
);
4520 rIter
->mpPage
->SetFollow(rIter
->mpPage
);
4522 if (rIter
->PageRestartNo())
4523 aRet
.SetNumOffset(rIter
->PageStartAt());
4529 void wwSectionManager::InsertSegments()
4531 mySegIter aEnd
= maSegments
.end();
4532 mySegIter aStart
= maSegments
.begin();
4533 for (mySegIter aIter
= aStart
; aIter
!= aEnd
; ++aIter
)
4535 // If the section is of type "New column" (0x01), then simply insert a column break.
4536 // But only if there actually are columns on the page, otherwise a column break
4537 // seems to be handled like a page break by MSO.
4538 if ( aIter
->maSep
.bkc
== 1 && aIter
->maSep
.ccolM1
> 0 )
4540 SwPaM
start( aIter
->maStart
);
4541 mrReader
.m_rDoc
.getIDocumentContentOperations().InsertPoolItem( start
, SvxFormatBreakItem(SvxBreak::ColumnBefore
, RES_BREAK
));
4545 mySegIter aNext
= aIter
+1;
4546 mySegIter aPrev
= (aIter
== aStart
) ? aIter
: aIter
-1;
4548 // If two following sections are different in following properties, Word will interpret a continuous
4549 // section break between them as if it was a section break next page.
4550 bool bThisAndPreviousAreCompatible
= ((aIter
->GetPageWidth() == aPrev
->GetPageWidth()) &&
4551 (aIter
->GetPageHeight() == aPrev
->GetPageHeight()) && (aIter
->IsLandScape() == aPrev
->IsLandScape()));
4553 bool bInsertSection
= (aIter
!= aStart
) && aIter
->IsContinuous() && bThisAndPreviousAreCompatible
;
4554 bool bInsertPageDesc
= !bInsertSection
;
4555 bool bProtected
= SectionIsProtected(*aIter
); // do we really need this ?? I guess I have a different logic in editshell which disables this...
4557 if (bInsertPageDesc
)
4560 If a cont section follows this section then we won't be
4561 creating a page desc with 2+ cols as we cannot host a one
4562 col section in a 2+ col pagedesc and make it look like
4563 word. But if the current section actually has columns then
4564 we are forced to insert a section here as well as a page
4568 bool bIgnoreCols
= bInsertSection
;
4569 bool bThisAndNextAreCompatible
= (aNext
== aEnd
) ||
4570 ((aIter
->GetPageWidth() == aNext
->GetPageWidth()) &&
4571 (aIter
->GetPageHeight() == aNext
->GetPageHeight()) &&
4572 (aIter
->IsLandScape() == aNext
->IsLandScape()));
4574 if ((aNext
!= aEnd
&& aNext
->IsContinuous() && bThisAndNextAreCompatible
) || bProtected
)
4577 if ((aIter
->NoCols() > 1) || bProtected
)
4578 bInsertSection
= true;
4581 SwFormatPageDesc
aDesc(SetSwFormatPageDesc(aIter
, aStart
, bIgnoreCols
));
4582 if (!aDesc
.GetPageDesc())
4585 // special case handling for odd/even section break
4586 // a) as before create a new page style for the section break
4587 // b) set Layout of generated page style to right/left ( according
4588 // to section break odd/even )
4589 // c) create a new style to follow the break page style
4590 if ( aIter
->maSep
.bkc
== 3 || aIter
->maSep
.bkc
== 4 )
4592 // SetSwFormatPageDesc calls some methods that could
4593 // modify aIter (e.g. wwSection ).
4594 // Since we call SetSwFormatPageDesc below to generate the
4595 // 'Following' style of the Break style, it is safer
4596 // to take a copy of the contents of aIter.
4597 wwSection aTmpSection
= *aIter
;
4598 // create a new following page style
4599 SwFormatPageDesc
aFollow(SetSwFormatPageDesc(aIter
, aStart
, bIgnoreCols
));
4600 // restore any contents of aIter trashed by SetSwFormatPageDesc
4601 *aIter
= std::move(aTmpSection
);
4603 // Handle the section break
4604 UseOnPage eUseOnPage
= UseOnPage::Left
;
4605 if ( aIter
->maSep
.bkc
== 4 ) // Odd ( right ) Section break
4606 eUseOnPage
= UseOnPage::Right
;
4608 // Keep the share flags.
4609 aDesc
.GetPageDesc()->SetUseOn( eUseOnPage
);
4610 aDesc
.GetPageDesc()->SetFollow( aFollow
.GetPageDesc() );
4613 // Avoid setting the page style at the very beginning since it is always the default style anyway,
4614 // unless it is needed to specify a page number.
4615 if (aIter
!= aStart
|| aDesc
.GetNumOffset())
4616 GiveNodePageDesc(aIter
->maStart
, aDesc
, mrReader
.m_rDoc
);
4619 SwTextNode
* pTextNd
= nullptr;
4622 // Start getting the bounds of this section
4623 SwPaM
aSectPaM(*mrReader
.m_pPaM
, mrReader
.m_pPaM
);
4624 SwNodeIndex
aAnchor(aSectPaM
.GetPoint()->GetNode());
4627 aAnchor
= aNext
->maStart
;
4628 aSectPaM
.GetPoint()->Assign(aAnchor
);
4629 aSectPaM
.Move(fnMoveBackward
);
4632 const SwPosition
* pPos
= aSectPaM
.GetPoint();
4633 SwTextNode
const*const pSttNd
= pPos
->GetNode().GetTextNode();
4634 const SwTableNode
* pTableNd
= pSttNd
? pSttNd
->FindTableNode() : nullptr;
4638 mrReader
.m_rDoc
.GetNodes().MakeTextNode(aAnchor
.GetNode(),
4639 mrReader
.m_rDoc
.getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_TEXT
));
4641 aSectPaM
.GetPoint()->Assign(*pTextNd
, 0);
4646 aSectPaM
.GetPoint()->Assign(aIter
->maStart
);
4648 bool bHasOwnHdFt
= false;
4650 In this nightmare scenario the continuous section has its own
4651 headers and footers so we will try and find a hard page break
4652 between here and the end of the section and put the headers and
4655 if (!bInsertPageDesc
)
4658 mrReader
.HasOwnHeaderFooter(
4659 aIter
->maSep
.grpfIhdt
& ~(WW8_HEADER_FIRST
| WW8_FOOTER_FIRST
),
4660 aIter
->maSep
.grpfIhdt
, std::distance(aStart
, aIter
)
4665 // #i40766# Need to cache the page descriptor in case there is
4666 // no page break in the section
4667 SwPageDesc
*pOrig
= aIter
->mpPage
;
4668 bool bFailed
= true;
4669 SwFormatPageDesc
aDesc(SetSwFormatPageDesc(aIter
, aStart
, true));
4670 if (aDesc
.GetPageDesc())
4672 SwNodeOffset nStart
= aSectPaM
.Start()->GetNodeIndex();
4673 SwNodeOffset nEnd
= aSectPaM
.End()->GetNodeIndex();
4674 for(; nStart
<= nEnd
; ++nStart
)
4676 SwNode
* pNode
= mrReader
.m_rDoc
.GetNodes()[nStart
];
4679 if (sw::util::HasPageBreak(*pNode
))
4681 SwNodeIndex
aIdx(*pNode
);
4682 GiveNodePageDesc(aIdx
, aDesc
, mrReader
.m_rDoc
);
4690 aIter
->mpPage
= pOrig
;
4694 // End getting the bounds of this section, quite a job eh?
4695 SwSectionFormat
*pRet
= InsertSection(aSectPaM
, *aIter
);
4696 // The last section if continuous is always unbalanced
4699 // Set the columns to be UnBalanced if that compatibility option is set
4700 if (mrReader
.m_xWDop
->fNoColumnBalance
)
4701 pRet
->SetFormatAttr(SwFormatNoBalancedColumns(true));
4704 // Otherwise set to unbalanced if the following section is
4705 // not continuous, (which also means that the last section
4707 if (aNext
== aEnd
|| !aNext
->IsContinuous())
4708 pRet
->SetFormatAttr(SwFormatNoBalancedColumns(true));
4715 SwPaM
aTest(*pTextNd
);
4716 mrReader
.m_rDoc
.getIDocumentContentOperations().DelFullPara(aTest
);
4722 void wwExtraneousParas::delete_all_from_doc()
4724 auto aEnd
= m_aTextNodes
.rend();
4725 for (auto aI
= m_aTextNodes
.rbegin(); aI
!= aEnd
; ++aI
)
4727 ExtraTextNodeListener
& rListener
= const_cast<ExtraTextNodeListener
&>(*aI
);
4728 SwTextNode
* pTextNode
= rListener
.GetTextNode();
4729 rListener
.StopListening(pTextNode
);
4731 SwPaM
aTest(*pTextNode
);
4732 m_rDoc
.getIDocumentContentOperations().DelFullPara(aTest
);
4734 m_aTextNodes
.clear();
4737 void wwExtraneousParas::insert(SwTextNode
*pTextNode
)
4739 m_aTextNodes
.emplace(pTextNode
, this);
4742 void wwExtraneousParas::remove_if_present(SwModify
* pModify
)
4744 auto it
= std::find_if(m_aTextNodes
.begin(), m_aTextNodes
.end(),
4745 [pModify
](const ExtraTextNodeListener
& rEntry
) { return rEntry
.GetTextNode() == pModify
; });
4746 if (it
== m_aTextNodes
.end())
4748 SAL_WARN("sw.ww8", "It is unexpected to drop a para scheduled for removal");
4749 m_aTextNodes
.erase(it
);
4752 TextNodeListener::TextNodeListener(SwTextNode
* pTextNode
)
4753 : m_pTextNode(pTextNode
)
4755 m_pTextNode
->Add(*this);
4758 TextNodeListener::~TextNodeListener()
4762 StopListening(m_pTextNode
);
4765 void TextNodeListener::SwClientNotify(const SwModify
& rModify
, const SfxHint
& rHint
)
4767 if (rHint
.GetId() != SfxHintId::SwLegacyModify
)
4769 auto pLegacy
= static_cast<const sw::LegacyModifyHint
*>(&rHint
);
4770 //Â ofz#41398 drop a para scheduled for deletion if something else deletes it
4771 // before wwExtraneousParas gets its chance to do so. Not the usual scenario,
4772 // indicates an underlying bug.
4773 if (pLegacy
->GetWhich() == RES_OBJECTDYING
)
4774 removed(const_cast<SwModify
*>(&rModify
));
4777 void TextNodeListener::StopListening(SwModify
* pTextNode
)
4779 pTextNode
->Remove(*this);
4780 m_pTextNode
= nullptr;
4783 void TextNodeListener::removed(SwModify
* pTextNode
)
4785 StopListening(pTextNode
);
4788 void wwExtraneousParas::ExtraTextNodeListener::removed(SwModify
* pTextNode
)
4790 m_pOwner
->remove_if_present(pTextNode
);
4793 void SwWW8ImplReader::StoreMacroCmds()
4795 if (!m_xWwFib
->m_lcbCmds
)
4798 bool bValidPos
= checkSeek(*m_pTableStream
, m_xWwFib
->m_fcCmds
);
4802 uno::Reference
< embed::XStorage
> xRoot(m_pDocShell
->GetStorage());
4809 uno::Reference
< io::XStream
> xStream
=
4810 xRoot
->openStreamElement( SL::aMSMacroCmds
, embed::ElementModes::READWRITE
);
4811 std::unique_ptr
<SvStream
> xOutStream(::utl::UcbStreamHelper::CreateStream(xStream
));
4813 sal_uInt32 lcbCmds
= std::min
<sal_uInt32
>(m_xWwFib
->m_lcbCmds
, m_pTableStream
->remainingSize());
4814 std::unique_ptr
<sal_uInt8
[]> xBuffer(new sal_uInt8
[lcbCmds
]);
4815 m_xWwFib
->m_lcbCmds
= m_pTableStream
->ReadBytes(xBuffer
.get(), lcbCmds
);
4816 xOutStream
->WriteBytes(xBuffer
.get(), m_xWwFib
->m_lcbCmds
);
4823 void SwWW8ImplReader::ReadDocVars()
4825 std::vector
<OUString
> aDocVarStrings
;
4826 std::vector
<ww::bytes
> aDocVarStringIds
;
4827 std::vector
<OUString
> aDocValueStrings
;
4828 WW8ReadSTTBF(!m_bVer67
, *m_pTableStream
, m_xWwFib
->m_fcStwUser
,
4829 m_xWwFib
->m_lcbStwUser
, m_bVer67
? 2 : 0, m_eStructCharSet
,
4830 aDocVarStrings
, &aDocVarStringIds
, &aDocValueStrings
);
4831 if (m_bVer67
) return;
4833 uno::Reference
< text::XTextFieldsSupplier
> xFieldsSupplier(m_pDocShell
->GetModel(), uno::UNO_QUERY_THROW
);
4834 uno::Reference
<css::lang::XMultiServiceFactory
> xTextFactory(m_pDocShell
->GetModel(), uno::UNO_QUERY
);
4835 uno::Reference
< container::XNameAccess
> xFieldMasterAccess
= xFieldsSupplier
->getTextFieldMasters();
4836 for(size_t i
= 0; i
< aDocVarStrings
.size(); i
++)
4838 const OUString
&rName
= aDocVarStrings
[i
];
4840 if (aDocValueStrings
.size() > i
)
4842 OUString value
= aDocValueStrings
[i
];
4843 value
= value
.replaceAll("\r\n", "\n");
4844 value
= value
.replaceAll("\r", "\n");
4845 // fdo48097-1.doc is an example of a case needing sanitizeStringSurrogates
4846 aValue
<<= comphelper::string::sanitizeStringSurrogates(value
);
4849 uno::Reference
< beans::XPropertySet
> xMaster
;
4850 OUString
sFieldMasterService("com.sun.star.text.FieldMaster.User." + rName
);
4852 // Find or create Field Master
4853 if (xFieldMasterAccess
->hasByName(sFieldMasterService
))
4855 xMaster
.set(xFieldMasterAccess
->getByName(sFieldMasterService
), uno::UNO_QUERY_THROW
);
4859 xMaster
.set(xTextFactory
->createInstance(u
"com.sun.star.text.FieldMaster.User"_ustr
), uno::UNO_QUERY_THROW
);
4860 xMaster
->setPropertyValue(u
"Name"_ustr
, uno::Any(rName
));
4862 xMaster
->setPropertyValue(u
"Content"_ustr
, aValue
);
4869 void SwWW8ImplReader::ReadDocInfo()
4874 uno::Reference
<document::XDocumentPropertiesSupplier
> xDPS(
4875 m_pDocShell
->GetModel(), uno::UNO_QUERY_THROW
);
4876 uno::Reference
<document::XDocumentProperties
> xDocProps(
4877 xDPS
->getDocumentProperties());
4878 OSL_ENSURE(xDocProps
.is(), "DocumentProperties is null");
4880 if (!xDocProps
.is())
4883 if ( m_xWwFib
->m_fDot
)
4885 SfxMedium
* pMedium
= m_pDocShell
->GetMedium();
4888 const OUString
& aName
= pMedium
->GetName();
4889 INetURLObject
aURL( aName
);
4890 OUString sTemplateURL
= aURL
.GetMainURL(INetURLObject::DecodeMechanism::ToIUri
);
4891 if ( !sTemplateURL
.isEmpty() )
4892 xDocProps
->setTemplateURL( sTemplateURL
);
4895 else if (m_xWwFib
->m_lcbSttbfAssoc
) // not a template, and has a SttbfAssoc
4897 auto nCur
= m_pTableStream
->Tell();
4899 // point at tgc record
4900 if (!checkSeek(*m_pTableStream
, m_xWwFib
->m_fcSttbfAssoc
) || !aSttb
.Read(*m_pTableStream
))
4901 SAL_WARN("sw.ww8", "** Read of SttbAssoc data failed!!!! ");
4902 m_pTableStream
->Seek( nCur
); // return to previous position, is that necessary?
4903 OUString sPath
= aSttb
.getStringAtIndex( 0x1 );
4905 // attempt to convert to url (won't work for obvious reasons on linux)
4906 if ( !sPath
.isEmpty() )
4907 osl::FileBase::getFileURLFromSystemPath( sPath
, aURL
);
4909 xDocProps
->setTemplateURL( aURL
);
4911 xDocProps
->setTemplateURL( sPath
);
4914 sfx2::LoadOlePropertySet(xDocProps
, m_pStg
);
4917 static void lcl_createTemplateToProjectEntry( const uno::Reference
< container::XNameContainer
>& xPrjNameCache
, const OUString
& sTemplatePathOrURL
, const OUString
& sVBAProjName
)
4919 if ( !xPrjNameCache
.is() )
4923 aObj
.SetURL( sTemplatePathOrURL
);
4924 bool bIsURL
= aObj
.GetProtocol() != INetProtocol::NotValid
;
4927 aURL
= sTemplatePathOrURL
;
4930 osl::FileBase::getFileURLFromSystemPath( sTemplatePathOrURL
, aURL
);
4931 aObj
.SetURL( aURL
);
4935 OUString templateNameWithExt
= aObj
.GetLastName();
4936 sal_Int32 nIndex
= templateNameWithExt
.lastIndexOf( '.' );
4939 OUString templateName
= templateNameWithExt
.copy( 0, nIndex
);
4940 xPrjNameCache
->insertByName( templateName
, uno::Any( sVBAProjName
) );
4943 catch( const uno::Exception
& )
4950 class WW8Customizations
4952 SvStream
* mpTableStream
;
4955 WW8Customizations( SvStream
*, WW8Fib
const & );
4956 void Import( SwDocShell
* pShell
);
4961 WW8Customizations::WW8Customizations( SvStream
* pTableStream
, WW8Fib
const & rFib
) : mpTableStream(pTableStream
), mWw8Fib( rFib
)
4965 void WW8Customizations::Import( SwDocShell
* pShell
)
4967 if ( mWw8Fib
.m_lcbCmds
== 0 || !IsEightPlus(mWw8Fib
.GetFIBVersion()) )
4972 sal_uInt64 nCur
= mpTableStream
->Tell();
4973 if (!checkSeek(*mpTableStream
, mWw8Fib
.m_fcCmds
)) // point at tgc record
4975 SAL_WARN("sw.ww8", "** Seek to Customization data failed!!!! ");
4978 bool bReadResult
= aTCG
.Read( *mpTableStream
);
4979 mpTableStream
->Seek( nCur
); // return to previous position, is that necessary?
4982 SAL_WARN("sw.ww8", "** Read of Customization data failed!!!! ");
4985 aTCG
.ImportCustomToolBar( *pShell
);
4989 SAL_WARN("sw.ww8", "** Read of Customization data failed!!!! epically");
4993 void SwWW8ImplReader::ReadGlobalTemplateSettings( std::u16string_view sCreatedFrom
, const uno::Reference
< container::XNameContainer
>& xPrjNameCache
)
4998 SvtPathOptions aPathOpt
;
4999 const OUString
& aAddinPath
= aPathOpt
.GetAddinPath();
5000 uno::Sequence
< OUString
> sGlobalTemplates
;
5002 // first get the autoload addins in the directory STARTUP
5003 uno::Reference
<ucb::XSimpleFileAccess3
> xSFA(ucb::SimpleFileAccess::create(::comphelper::getProcessComponentContext()));
5005 if( xSFA
->isFolder( aAddinPath
) )
5006 sGlobalTemplates
= xSFA
->getFolderContents( aAddinPath
, false );
5008 for (const auto& rGlobalTemplate
: sGlobalTemplates
)
5011 aObj
.SetURL( rGlobalTemplate
);
5012 bool bIsURL
= aObj
.GetProtocol() != INetProtocol::NotValid
;
5015 aURL
= rGlobalTemplate
;
5017 osl::FileBase::getFileURLFromSystemPath( rGlobalTemplate
, aURL
);
5018 if ( !aURL
.endsWithIgnoreAsciiCase( ".dot" ) || ( !sCreatedFrom
.empty() && sCreatedFrom
== aURL
) )
5019 continue; // don't try and read the same document as ourselves
5021 rtl::Reference
<SotStorage
> rRoot
= new SotStorage(aURL
, StreamMode::STD_READWRITE
);
5023 BasicProjImportHelper
aBasicImporter( *m_pDocShell
);
5024 // Import vba via oox filter
5025 aBasicImporter
.import( m_pDocShell
->GetMedium()->GetInputStream() );
5026 lcl_createTemplateToProjectEntry( xPrjNameCache
, aURL
, aBasicImporter
.getProjectName() );
5027 // Read toolbars & menus
5028 rtl::Reference
<SotStorageStream
> refMainStream
= rRoot
->OpenSotStream(u
"WordDocument"_ustr
);
5029 refMainStream
->SetEndian(SvStreamEndian::LITTLE
);
5030 WW8Fib
aWwFib( *refMainStream
, 8 );
5031 rtl::Reference
<SotStorageStream
> xTableStream
=
5032 rRoot
->OpenSotStream(aWwFib
.m_fWhichTableStm
? SL::a1Table
: SL::a0Table
, StreamMode::STD_READ
);
5034 if (xTableStream
.is() && ERRCODE_NONE
== xTableStream
->GetError())
5036 xTableStream
->SetEndian(SvStreamEndian::LITTLE
);
5037 WW8Customizations
aGblCustomisations( xTableStream
.get(), aWwFib
);
5038 aGblCustomisations
.Import( m_pDocShell
);
5043 ErrCode
SwWW8ImplReader::CoreLoad(WW8Glossary
const *pGloss
)
5045 m_rDoc
.SetDocumentType( SwDoc::DOCTYPE_MSWORD
);
5046 if (m_bNewDoc
&& m_pStg
&& !pGloss
)
5048 // Initialize RDF metadata, to be able to add statements during the import.
5051 rtl::Reference
<SwXTextDocument
> const xModel(m_rDoc
.GetDocShell()->GetBaseModel());
5052 const uno::Reference
<uno::XComponentContext
>& xComponentContext(comphelper::getProcessComponentContext());
5053 uno::Reference
<embed::XStorage
> xStorage
= comphelper::OStorageHelper::GetTemporaryStorage();
5054 const uno::Reference
<rdf::XURI
> xBaseURI(sfx2::createBaseURI(xComponentContext
, static_cast<SfxBaseModel
*>(xModel
.get()), m_sBaseURL
));
5055 uno::Reference
<task::XInteractionHandler
> xHandler
;
5056 xModel
->loadMetadataFromStorage(xStorage
, xBaseURI
, xHandler
);
5058 catch (const uno::Exception
&)
5060 TOOLS_WARN_EXCEPTION("sw.ww8", "failed to initialize RDF metadata");
5065 auto pFibData
= std::make_shared
<::ww8::WW8FibData
>();
5067 if (m_xWwFib
->m_fReadOnlyRecommended
)
5068 pFibData
->setReadOnlyRecommended(true);
5070 pFibData
->setReadOnlyRecommended(false);
5072 if (m_xWwFib
->m_fWriteReservation
)
5073 pFibData
->setWriteReservation(true);
5075 pFibData
->setWriteReservation(false);
5077 m_rDoc
.getIDocumentExternalData().setExternalData(::sw::tExternalDataType::FIB
, pFibData
);
5079 ::sw::tExternalDataPointer pSttbfAsoc
5080 = std::make_shared
<::ww8::WW8Sttb
<ww8::WW8Struct
>>(*m_pTableStream
, m_xWwFib
->m_fcSttbfAssoc
, m_xWwFib
->m_lcbSttbfAssoc
);
5082 m_rDoc
.getIDocumentExternalData().setExternalData(::sw::tExternalDataType::STTBF_ASSOC
, pSttbfAsoc
);
5084 if (m_xWwFib
->m_fWriteReservation
|| m_xWwFib
->m_fReadOnlyRecommended
)
5086 SwDocShell
* pDocShell
= m_rDoc
.GetDocShell();
5088 pDocShell
->SetReadOnlyUI();
5091 m_pPaM
= mpCursor
.get();
5093 m_xCtrlStck
.reset(new SwWW8FltControlStack(m_rDoc
, m_nFieldFlags
, *this));
5095 m_xRedlineStack
.reset(new sw::util::RedlineStack(m_rDoc
));
5098 RefFieldStck: Keeps track of bookmarks which may be inserted as
5101 m_xReffedStck
.reset(new SwWW8ReferencedFltEndStack(m_rDoc
, m_nFieldFlags
));
5102 m_xReffingStck
.reset(new SwWW8FltRefStack(m_rDoc
, m_nFieldFlags
));
5104 m_xAnchorStck
.reset(new SwWW8FltAnchorStack(m_rDoc
, m_nFieldFlags
));
5106 size_t nPageDescOffset
= m_rDoc
.GetPageDescCnt();
5108 RedlineFlags eMode
= RedlineFlags::ShowInsert
| RedlineFlags::ShowDelete
;
5110 m_oSprmParser
.emplace(*m_xWwFib
);
5112 // Set handy helper variables
5113 m_bVer6
= (6 == m_xWwFib
->m_nVersion
);
5114 m_bVer7
= (7 == m_xWwFib
->m_nVersion
);
5115 m_bVer67
= m_bVer6
|| m_bVer7
;
5116 m_bVer8
= (8 == m_xWwFib
->m_nVersion
);
5118 m_eTextCharSet
= WW8Fib::GetFIBCharset(m_xWwFib
->m_chse
, m_xWwFib
->m_lid
);
5119 m_eStructCharSet
= WW8Fib::GetFIBCharset(m_xWwFib
->m_chseTables
, m_xWwFib
->m_lid
);
5121 m_bWWBugNormal
= m_xWwFib
->m_nProduct
== 0xc03d;
5123 m_xProgress
.reset(new ImportProgress(m_pDocShell
, 0, 100));
5126 m_xFonts
.reset(new WW8Fonts(*m_pTableStream
, *m_xWwFib
));
5128 // Document Properties
5129 m_xWDop
.reset(new WW8Dop(*m_pTableStream
, m_xWwFib
->m_nFib
, m_xWwFib
->m_fcDop
,
5130 m_xWwFib
->m_lcbDop
));
5136 Import revisioning data: author names
5138 if( m_xWwFib
->m_lcbSttbfRMark
)
5140 ReadRevMarkAuthorStrTabl(*m_pTableStream
,
5141 m_xWwFib
->m_fcSttbfRMark
,
5142 m_xWwFib
->m_lcbSttbfRMark
, m_rDoc
);
5145 // Initialize our String/ID map for Linked Sections
5146 std::vector
<OUString
> aLinkStrings
;
5147 std::vector
<ww::bytes
> aStringIds
;
5149 WW8ReadSTTBF(!m_bVer67
, *m_pTableStream
, m_xWwFib
->m_fcSttbFnm
,
5150 m_xWwFib
->m_lcbSttbFnm
, m_bVer67
? 2 : 0, m_eStructCharSet
,
5151 aLinkStrings
, &aStringIds
);
5153 for (size_t i
=0; i
< aLinkStrings
.size() && i
< aStringIds
.size(); ++i
)
5155 const ww::bytes
& stringId
= aStringIds
[i
];
5156 if (stringId
.size() < sizeof(WW8_STRINGID
))
5158 SAL_WARN("sw.ww8", "SwWW8ImplReader::CoreLoad: WW8_STRINGID is too short");
5161 const WW8_STRINGID
*stringIdStruct
= reinterpret_cast<const WW8_STRINGID
*>(stringId
.data());
5162 m_aLinkStringMap
[SVBT16ToUInt16(stringIdStruct
->nStringId
)] = aLinkStrings
[i
];
5165 ReadDocVars(); // import document variables as meta information.
5167 m_xProgress
->Update(m_nProgress
); // Update
5169 m_xLstManager
.reset(new WW8ListManager(*m_pTableStream
, *this));
5172 first (1) import all styles (see WW8PAR2.CXX)
5173 BEFORE the import of the lists !!
5175 m_xProgress
->Update(m_nProgress
); // Update
5176 m_xStyles
.reset(new WW8RStyle(*m_xWwFib
, this)); // Styles
5177 m_xStyles
->Import();
5180 In the end: (also see WW8PAR3.CXX)
5182 Go through all Styles and attach respective List Format
5183 AFTER we imported the Styles and AFTER we imported the Lists!
5185 m_xProgress
->Update(m_nProgress
); // Update
5186 m_xStyles
->PostProcessStyles();
5188 if (!m_vColl
.empty())
5191 m_xSBase
.reset(new WW8ScannerBase(m_pStrm
,m_pTableStream
,m_pDataStream
, m_xWwFib
.get()));
5193 if (m_xSBase
->AreThereFootnotes())
5195 static const SwFootnoteNum eNumA
[4] =
5197 FTNNUM_DOC
, FTNNUM_CHAPTER
, FTNNUM_PAGE
, FTNNUM_DOC
5200 SwFootnoteInfo aInfo
= m_rDoc
.GetFootnoteInfo(); // Copy-Ctor private
5202 aInfo
.m_ePos
= FTNPOS_PAGE
;
5203 aInfo
.m_eNum
= eNumA
[m_xWDop
->rncFootnote
];
5204 sal_uInt16 nfcFootnoteRef
= m_xWDop
->nfcFootnoteRef
;
5205 aInfo
.m_aFormat
.SetNumberingType(WW8ListManager::GetSvxNumTypeFromMSONFC(nfcFootnoteRef
));
5206 if( m_xWDop
->nFootnote
)
5207 aInfo
.m_nFootnoteOffset
= m_xWDop
->nFootnote
- 1;
5208 m_rDoc
.SetFootnoteInfo( aInfo
);
5210 if (m_xSBase
->AreThereEndnotes())
5212 SwEndNoteInfo aInfo
= m_rDoc
.GetEndNoteInfo(); // Same as for Footnote
5213 sal_uInt16 nfcEdnRef
= m_xWDop
->nfcEdnRef
;
5214 aInfo
.m_aFormat
.SetNumberingType(WW8ListManager::GetSvxNumTypeFromMSONFC(nfcEdnRef
));
5216 aInfo
.m_nFootnoteOffset
= m_xWDop
->nEdn
- 1;
5217 m_rDoc
.SetEndNoteInfo( aInfo
);
5220 if (m_xWwFib
->m_lcbPlcfhdd
)
5221 m_xHdFt
.reset(new WW8PLCF_HdFt(m_pTableStream
, *m_xWwFib
, *m_xWDop
));
5225 // inserting into an existing document:
5226 // As only complete paragraphs are inserted, the current one
5227 // needs to be split - once or even twice.
5228 const SwPosition
* pPos
= m_pPaM
->GetPoint();
5230 // split current paragraph to get new paragraph for the insertion
5231 m_rDoc
.getIDocumentContentOperations().SplitNode( *pPos
, false );
5233 // another split, if insertion position was not at the end of the current paragraph.
5234 SwTextNode
const*const pTextNd
= pPos
->GetNode().GetTextNode();
5235 if ( pTextNd
->GetText().getLength() )
5237 m_rDoc
.getIDocumentContentOperations().SplitNode( *pPos
, false );
5238 // move PaM back to the newly empty paragraph
5239 m_pPaM
->Move( fnMoveBackward
);
5242 // suppress insertion of tables inside footnotes.
5243 const SwNodeOffset nNd
= pPos
->GetNodeIndex();
5244 m_bReadNoTable
= ( nNd
< m_rDoc
.GetNodes().GetEndOfInserts().GetIndex() &&
5245 m_rDoc
.GetNodes().GetEndOfInserts().StartOfSectionIndex() < nNd
);
5248 m_xProgress
->Update(m_nProgress
); // Update
5250 // loop for each glossary entry and add dummy section node
5253 WW8PLCF
aPlc(*m_pTableStream
, m_xWwFib
->m_fcPlcfglsy
, m_xWwFib
->m_lcbPlcfglsy
, 0);
5255 WW8_CP nStart
, nEnd
;
5258 for (int i
= 0; i
< pGloss
->GetNoStrings(); ++i
, aPlc
.advance())
5260 SwNodeIndex
aIdx( m_rDoc
.GetNodes().GetEndOfContent());
5261 SwTextFormatColl
* pColl
=
5262 m_rDoc
.getIDocumentStylePoolAccess().GetTextCollFromPool(RES_POOLCOLL_STANDARD
,
5264 SwStartNode
*pNode
=
5265 m_rDoc
.GetNodes().MakeTextSection(aIdx
.GetNode(),
5266 SwNormalStartNode
,pColl
);
5267 m_pPaM
->GetPoint()->Assign( pNode
->GetIndex()+1 );
5268 aPlc
.Get( nStart
, nEnd
, pDummy
);
5269 ReadText(nStart
,nEnd
-nStart
-1,MAN_MAINTEXT
);
5272 else // ordinary case
5274 if (m_bNewDoc
&& m_pStg
) /*meaningless for a glossary */
5276 m_pDocShell
->SetIsTemplate( m_xWwFib
->m_fDot
); // point at tgc record
5277 uno::Reference
<document::XDocumentPropertiesSupplier
> const
5278 xDocPropSupp(m_pDocShell
->GetModel(), uno::UNO_QUERY_THROW
);
5279 uno::Reference
< document::XDocumentProperties
> xDocProps( xDocPropSupp
->getDocumentProperties(), uno::UNO_SET_THROW
);
5281 OUString sCreatedFrom
= xDocProps
->getTemplateURL();
5282 uno::Reference
< container::XNameContainer
> xPrjNameCache
;
5283 uno::Reference
< lang::XMultiServiceFactory
> xSF(m_pDocShell
->GetModel(), uno::UNO_QUERY
);
5285 xPrjNameCache
.set( xSF
->createInstance( u
"ooo.vba.VBAProjectNameProvider"_ustr
), uno::UNO_QUERY
);
5287 // Read Global templates
5288 ReadGlobalTemplateSettings( sCreatedFrom
, xPrjNameCache
);
5290 // Create and insert Word vba Globals
5292 uno::Sequence
< uno::Any
> aArgs
{ uno::Any(m_pDocShell
->GetModel()) };
5295 aGlobs
<<= ::comphelper::getProcessServiceFactory()->createInstanceWithArguments( u
"ooo.vba.word.Globals"_ustr
, aArgs
);
5297 catch (const uno::Exception
&)
5299 SAL_WARN("sw.ww8", "SwWW8ImplReader::CoreLoad: ooo.vba.word.Globals is not available");
5302 #if HAVE_FEATURE_SCRIPTING
5305 BasicManager
*pBasicMan
= m_pDocShell
->GetBasicManager();
5307 pBasicMan
->SetGlobalUNOConstant( u
"VBAGlobals"_ustr
, aGlobs
);
5310 BasicProjImportHelper
aBasicImporter( *m_pDocShell
);
5311 // Import vba via oox filter
5312 bool bRet
= aBasicImporter
.import( m_pDocShell
->GetMedium()->GetInputStream() );
5314 lcl_createTemplateToProjectEntry( xPrjNameCache
, sCreatedFrom
, aBasicImporter
.getProjectName() );
5315 WW8Customizations
aCustomisations( m_pTableStream
, *m_xWwFib
);
5316 aCustomisations
.Import( m_pDocShell
);
5319 m_rDoc
.SetContainsMSVBasic(true);
5323 ReadText(0, m_xWwFib
->m_ccpText
, MAN_MAINTEXT
);
5326 m_xProgress
->Update(m_nProgress
); // Update
5328 if (m_pDrawPg
&& m_xMSDffManager
&& m_xMSDffManager
->GetShapeOrders())
5330 // Helper array to chain the inserted frames (instead of SdrTextObj)
5331 SvxMSDffShapeTxBxSort aTxBxSort
;
5333 // Ensure correct z-order of read Escher objects
5334 sal_uInt16 nShapeCount
= m_xMSDffManager
->GetShapeOrders()->size();
5336 for (sal_uInt16 nShapeNum
=0; nShapeNum
< nShapeCount
; nShapeNum
++)
5338 SvxMSDffShapeOrder
*pOrder
=
5339 (*m_xMSDffManager
->GetShapeOrders())[nShapeNum
].get();
5340 // Insert Pointer into new Sort array
5341 if (pOrder
->nTxBxComp
&& pOrder
->pFly
)
5342 aTxBxSort
.insert(pOrder
);
5345 if( !aTxBxSort
.empty() )
5347 SwFormatChain aChain
;
5348 for( SvxMSDffShapeTxBxSort::iterator it
= aTxBxSort
.begin(); it
!= aTxBxSort
.end(); ++it
)
5350 SvxMSDffShapeOrder
*pOrder
= *it
;
5352 // Initialize FlyFrame Formats
5353 SwFlyFrameFormat
* pFlyFormat
= pOrder
->pFly
;
5354 SwFlyFrameFormat
* pNextFlyFormat
= nullptr;
5355 SwFlyFrameFormat
* pPrevFlyFormat
= nullptr;
5357 // Determine successor, if we can
5358 SvxMSDffShapeTxBxSort::iterator tmpIter1
= it
;
5360 if( tmpIter1
!= aTxBxSort
.end() )
5362 SvxMSDffShapeOrder
*pNextOrder
= *tmpIter1
;
5363 if ((0xFFFF0000 & pOrder
->nTxBxComp
)
5364 == (0xFFFF0000 & pNextOrder
->nTxBxComp
))
5365 pNextFlyFormat
= pNextOrder
->pFly
;
5367 // Determine predecessor, if we can
5368 if( it
!= aTxBxSort
.begin() )
5370 SvxMSDffShapeTxBxSort::iterator tmpIter2
= it
;
5372 SvxMSDffShapeOrder
*pPrevOrder
= *tmpIter2
;
5373 if ((0xFFFF0000 & pOrder
->nTxBxComp
)
5374 == (0xFFFF0000 & pPrevOrder
->nTxBxComp
))
5375 pPrevFlyFormat
= pPrevOrder
->pFly
;
5377 // If successor or predecessor present, insert the
5378 // chain at the FlyFrame Format
5379 if (pNextFlyFormat
|| pPrevFlyFormat
)
5381 aChain
.SetNext( pNextFlyFormat
);
5382 aChain
.SetPrev( pPrevFlyFormat
);
5383 pFlyFormat
->SetFormatAttr( aChain
);
5389 bool isHideRedlines(false);
5393 if( m_xWDop
->fRevMarking
)
5394 eMode
|= RedlineFlags::On
;
5395 isHideRedlines
= !m_xWDop
->fRMView
;
5398 m_aInsertedTables
.DelAndMakeTableFrames();
5399 m_aSectionManager
.InsertSegments();
5405 m_xFormImpl
.reset();
5407 m_xMSDffManager
.reset();
5412 m_xAtnNames
.reset();
5413 m_oSprmParser
.reset();
5414 m_xProgress
.reset();
5416 m_pDataStream
= nullptr;
5417 m_pTableStream
= nullptr;
5420 DeleteAnchorStack();
5422 m_oLastAnchorPos
.reset();//ensure this is deleted before UpdatePageDescs
5423 // ofz#10994 remove any trailing fly paras before processing redlines
5424 m_xWFlyPara
.reset();
5425 // ofz#12660 remove any trailing fly paras before deleting extra paras
5426 m_xSFlyPara
.reset();
5427 // remove extra paragraphs after attribute ctrl
5428 // stacks etc. are destroyed, and before fields
5430 m_aExtraneousParas
.delete_all_from_doc();
5431 m_xRedlineStack
->closeall(*m_pPaM
->GetPoint());
5433 // For i120928,achieve the graphics from the special bookmark with is for graphic bullet
5435 std::vector
<const SwGrfNode
*> vecBulletGrf
;
5436 std::vector
<SwFrameFormat
*> vecFrameFormat
;
5438 IDocumentMarkAccess
* const pMarkAccess
= m_rDoc
.getIDocumentMarkAccess();
5441 auto ppBkmk
= pMarkAccess
->findBookmark( u
"_PictureBullets"_ustr
);
5442 if ( ppBkmk
!= pMarkAccess
->getBookmarksEnd() &&
5443 IDocumentMarkAccess::GetType(**ppBkmk
) == IDocumentMarkAccess::MarkType::BOOKMARK
)
5445 SwTextNode
* pTextNode
= (*ppBkmk
)->GetMarkStart().GetNode().GetTextNode();
5449 const SwpHints
* pHints
= pTextNode
->GetpSwpHints();
5450 for( size_t nHintPos
= 0; pHints
&& nHintPos
< pHints
->Count(); ++nHintPos
)
5452 const SwTextAttr
*pHt
= pHints
->Get(nHintPos
);
5453 if (pHt
->Which() != RES_TXTATR_FLYCNT
)
5455 const sal_Int32 st
= pHt
->GetStart();
5456 if (st
>= (*ppBkmk
)->GetMarkStart().GetContentIndex())
5458 SwFrameFormat
* pFrameFormat
= pHt
->GetFlyCnt().GetFrameFormat();
5459 vecFrameFormat
.push_back(pFrameFormat
);
5460 const SwNodeIndex
* pNdIdx
= pFrameFormat
->GetContent().GetContentIdx();
5461 const SwNodes
* pNodesArray
= (pNdIdx
!= nullptr)
5462 ? &(pNdIdx
->GetNodes())
5464 const SwGrfNode
*pGrf
= (pNodesArray
!= nullptr)
5465 ? (*pNodesArray
)[pNdIdx
->GetIndex() + 1]->GetGrfNode()
5467 vecBulletGrf
.push_back(pGrf
);
5470 // update graphic bullet information
5471 size_t nCount
= m_xLstManager
->GetWW8LSTInfoNum();
5472 for (size_t i
= 0; i
< nCount
; ++i
)
5474 SwNumRule
* pRule
= m_xLstManager
->GetNumRule(i
);
5475 for (sal_uInt16 j
= 0; j
< MAXLEVEL
; ++j
)
5477 SwNumFormat
aNumFormat(pRule
->Get(j
));
5478 const sal_Int16 nType
= aNumFormat
.GetNumberingType();
5479 const sal_uInt16 nGrfBulletCP
= aNumFormat
.GetGrfBulletCP();
5480 if ( nType
== SVX_NUM_BITMAP
5481 && vecBulletGrf
.size() > nGrfBulletCP
5482 && vecBulletGrf
[nGrfBulletCP
] != nullptr )
5484 Graphic aGraphic
= vecBulletGrf
[nGrfBulletCP
]->GetGrf();
5485 SvxBrushItem
aBrush(aGraphic
, GPOS_AREA
, SID_ATTR_BRUSH
);
5486 const vcl::Font
& aFont
= numfunc::GetDefBulletFont();
5487 int nHeight
= aFont
.GetFontHeight() * 12;
5488 Size
aPrefSize( aGraphic
.GetPrefSize());
5489 if (aPrefSize
.Height() * aPrefSize
.Width() != 0 )
5491 int nWidth
= (nHeight
* aPrefSize
.Width()) / aPrefSize
.Height();
5492 Size
aSize(nWidth
, nHeight
);
5493 aNumFormat
.SetGraphicBrush(&aBrush
, &aSize
);
5497 aNumFormat
.SetNumberingType(SVX_NUM_CHAR_SPECIAL
);
5498 aNumFormat
.SetBulletChar(0x2190);
5500 pRule
->Set( j
, aNumFormat
);
5504 // Remove additional pictures
5505 for (SwFrameFormat
* p
: vecFrameFormat
)
5507 m_rDoc
.getIDocumentLayoutAccess().DelLayoutFormat(p
);
5512 m_xLstManager
.reset();
5515 m_oPosAfterTOC
.reset();
5516 m_xRedlineStack
.reset();
5522 // delete the pam before the call for hide all redlines (Bug 73683)
5524 m_rDoc
.getIDocumentRedlineAccess().SetRedlineFlags(eMode
);
5526 UpdatePageDescs(m_rDoc
, nPageDescOffset
);
5528 // can't set it on the layout or view shell because it doesn't exist yet
5529 m_rDoc
.GetDocumentRedlineManager().SetHideRedlines(isHideRedlines
);
5531 return ERRCODE_NONE
;
5534 ErrCode
SwWW8ImplReader::SetSubStreams(rtl::Reference
<SotStorageStream
>& rTableStream
,
5535 rtl::Reference
<SotStorageStream
>& rDataStream
)
5537 ErrCode nErrRet
= ERRCODE_NONE
;
5538 // 6 stands for "6 OR 7", 7 stands for "ONLY 7"
5539 switch (m_xWwFib
->m_nVersion
)
5543 m_pTableStream
= m_pStrm
;
5544 m_pDataStream
= m_pStrm
;
5549 OSL_ENSURE( m_pStg
, "Version 8 always needs to have a Storage!!" );
5550 nErrRet
= ERR_SWG_READ_ERROR
;
5554 rTableStream
= m_pStg
->OpenSotStream(
5555 m_xWwFib
->m_fWhichTableStm
? SL::a1Table
: SL::a0Table
,
5556 StreamMode::STD_READ
);
5558 m_pTableStream
= rTableStream
.get();
5559 m_pTableStream
->SetEndian( SvStreamEndian::LITTLE
);
5561 rDataStream
= m_pStg
->OpenSotStream(SL::aData
, StreamMode::STD_READ
);
5563 if (rDataStream
.is() && ERRCODE_NONE
== rDataStream
->GetError())
5565 m_pDataStream
= rDataStream
.get();
5566 m_pDataStream
->SetEndian(SvStreamEndian::LITTLE
);
5569 m_pDataStream
= m_pStrm
;
5573 OSL_ENSURE( false, "We forgot to encode nVersion!" );
5574 nErrRet
= ERR_SWG_READ_ERROR
;
5582 SvStream
* MakeTemp(std::optional
<utl::TempFileFast
>& roTempFile
)
5584 roTempFile
.emplace();
5585 return roTempFile
->GetStream(StreamMode::READWRITE
| StreamMode::SHARE_DENYWRITE
);
5588 #define WW_BLOCKSIZE 0x200
5590 void DecryptRC4(msfilter::MSCodec97
& rCtx
, SvStream
&rIn
, SvStream
&rOut
)
5592 const std::size_t nLen
= rIn
.TellEnd();
5595 sal_uInt8 in
[WW_BLOCKSIZE
];
5596 for (std::size_t nI
= 0, nBlock
= 0; nI
< nLen
; nI
+= WW_BLOCKSIZE
, ++nBlock
)
5598 std::size_t nBS
= std::min
<size_t>(nLen
- nI
, WW_BLOCKSIZE
);
5599 nBS
= rIn
.ReadBytes(in
, nBS
);
5600 rCtx
.InitCipher(nBlock
);
5601 rCtx
.Decode(in
, nBS
, in
, nBS
);
5602 rOut
.WriteBytes(in
, nBS
);
5606 void DecryptXOR(msfilter::MSCodec_XorWord95
&rCtx
, SvStream
&rIn
, SvStream
&rOut
)
5608 std::size_t nSt
= rIn
.Tell();
5609 std::size_t nLen
= rIn
.TellEnd();
5614 sal_uInt8 in
[0x4096];
5615 for (std::size_t nI
= nSt
; nI
< nLen
; nI
+= 0x4096)
5617 std::size_t nBS
= std::min
<size_t>(nLen
- nI
, 0x4096 );
5618 nBS
= rIn
.ReadBytes(in
, nBS
);
5619 rCtx
.Decode(in
, nBS
);
5620 rOut
.WriteBytes(in
, nBS
);
5624 // moan, copy and paste :-(
5625 OUString
QueryPasswordForMedium(SfxMedium
& rMedium
)
5629 if (const SfxStringItem
* pPasswordItem
= rMedium
.GetItemSet().GetItemIfSet(SID_PASSWORD
))
5630 aPassw
= pPasswordItem
->GetValue();
5635 uno::Reference
< task::XInteractionHandler
> xHandler( rMedium
.GetInteractionHandler() );
5638 rtl::Reference
<::comphelper::DocPasswordRequest
> pRequest
= new ::comphelper::DocPasswordRequest(
5639 ::comphelper::DocPasswordRequestType::MS
, task::PasswordRequestMode_PASSWORD_ENTER
,
5640 INetURLObject(rMedium
.GetOrigURL())
5641 .GetLastName(INetURLObject::DecodeMechanism::WithCharset
));
5643 xHandler
->handle( pRequest
);
5645 if( pRequest
->isPassword() )
5646 aPassw
= pRequest
->getPassword();
5649 catch( const uno::Exception
& )
5657 uno::Sequence
< beans::NamedValue
> InitXorWord95Codec( ::msfilter::MSCodec_XorWord95
& rCodec
, SfxMedium
& rMedium
, WW8Fib
const * pWwFib
)
5659 uno::Sequence
< beans::NamedValue
> aEncryptionData
;
5660 const SfxUnoAnyItem
* pEncryptionData
= rMedium
.GetItemSet().GetItem(SID_ENCRYPTIONDATA
, false);
5661 if ( pEncryptionData
&& ( pEncryptionData
->GetValue() >>= aEncryptionData
) && !rCodec
.InitCodec( aEncryptionData
) )
5662 aEncryptionData
.realloc( 0 );
5664 if ( !aEncryptionData
.hasElements() )
5666 OUString sUniPassword
= QueryPasswordForMedium( rMedium
);
5668 OString
sPassword(OUStringToOString(sUniPassword
,
5669 WW8Fib::GetFIBCharset(pWwFib
->m_chseTables
, pWwFib
->m_lid
)));
5671 sal_Int32 nLen
= sPassword
.getLength();
5674 sal_uInt8 pPassword
[16];
5675 memcpy(pPassword
, sPassword
.getStr(), nLen
);
5676 memset(pPassword
+nLen
, 0, sizeof(pPassword
)-nLen
);
5678 rCodec
.InitKey( pPassword
);
5679 aEncryptionData
= rCodec
.GetEncryptionData();
5681 // the export supports RC4 algorithm only, so we have to
5682 // generate the related EncryptionData as well, so that Save
5683 // can export the document without asking for a password;
5684 // as result there will be EncryptionData for both algorithms
5685 // in the MediaDescriptor
5686 ::msfilter::MSCodec_Std97 aCodec97
;
5688 sal_uInt8 pDocId
[ 16 ];
5689 if (rtl_random_getBytes(nullptr, pDocId
, 16) != rtl_Random_E_None
)
5691 throw uno::RuntimeException(u
"rtl_random_getBytes failed"_ustr
);
5694 sal_uInt16 pStd97Pass
[16] = {};
5695 for( sal_Int32 nChar
= 0; nChar
< nLen
; ++nChar
)
5696 pStd97Pass
[nChar
] = sUniPassword
[nChar
];
5698 aCodec97
.InitKey( pStd97Pass
, pDocId
);
5700 // merge the EncryptionData, there should be no conflicts
5701 ::comphelper::SequenceAsHashMap
aEncryptionHash( aEncryptionData
);
5702 aEncryptionHash
.update( ::comphelper::SequenceAsHashMap( aCodec97
.GetEncryptionData() ) );
5703 aEncryptionHash
>> aEncryptionData
;
5707 return aEncryptionData
;
5710 uno::Sequence
< beans::NamedValue
> Init97Codec(msfilter::MSCodec97
& rCodec
, sal_uInt8
const pDocId
[16], SfxMedium
& rMedium
)
5712 uno::Sequence
< beans::NamedValue
> aEncryptionData
;
5713 const SfxUnoAnyItem
* pEncryptionData
= rMedium
.GetItemSet().GetItem(SID_ENCRYPTIONDATA
, false);
5714 if ( pEncryptionData
&& ( pEncryptionData
->GetValue() >>= aEncryptionData
) && !rCodec
.InitCodec( aEncryptionData
) )
5715 aEncryptionData
.realloc( 0 );
5717 if ( !aEncryptionData
.hasElements() )
5719 OUString sUniPassword
= QueryPasswordForMedium( rMedium
);
5721 sal_Int32 nLen
= sUniPassword
.getLength();
5724 sal_uInt16 pPassword
[16] = {};
5725 for( sal_Int32 nChar
= 0; nChar
< nLen
; ++nChar
)
5726 pPassword
[nChar
] = sUniPassword
[nChar
];
5728 rCodec
.InitKey( pPassword
, pDocId
);
5729 aEncryptionData
= rCodec
.GetEncryptionData();
5733 return aEncryptionData
;
5737 //TO-DO: merge this with lclReadFilepass8_Strong in sc which uses a different
5739 static bool lclReadCryptoAPIHeader(msfilter::RC4EncryptionInfo
&info
, SvStream
&rStream
)
5741 //It is possible there are other variants in existence but these
5742 //are the defaults I get with Word 2013
5744 rStream
.ReadUInt32(info
.header
.flags
);
5745 if (oox::getFlag( info
.header
.flags
, msfilter::ENCRYPTINFO_EXTERNAL
))
5748 sal_uInt32
nHeaderSize(0);
5749 rStream
.ReadUInt32(nHeaderSize
);
5750 sal_uInt32 actualHeaderSize
= sizeof(info
.header
);
5752 if (nHeaderSize
< actualHeaderSize
)
5755 rStream
.ReadUInt32(info
.header
.flags
);
5756 rStream
.ReadUInt32(info
.header
.sizeExtra
);
5757 rStream
.ReadUInt32(info
.header
.algId
);
5758 rStream
.ReadUInt32(info
.header
.algIdHash
);
5759 rStream
.ReadUInt32(info
.header
.keyBits
);
5760 rStream
.ReadUInt32(info
.header
.providedType
);
5761 rStream
.ReadUInt32(info
.header
.reserved1
);
5762 rStream
.ReadUInt32(info
.header
.reserved2
);
5764 rStream
.SeekRel(nHeaderSize
- actualHeaderSize
);
5766 rStream
.ReadUInt32(info
.verifier
.saltSize
);
5767 if (info
.verifier
.saltSize
!= msfilter::SALT_LENGTH
)
5769 rStream
.ReadBytes(&info
.verifier
.salt
, sizeof(info
.verifier
.salt
));
5770 rStream
.ReadBytes(&info
.verifier
.encryptedVerifier
, sizeof(info
.verifier
.encryptedVerifier
));
5772 rStream
.ReadUInt32(info
.verifier
.encryptedVerifierHashSize
);
5773 if (info
.verifier
.encryptedVerifierHashSize
!= RTL_DIGEST_LENGTH_SHA1
)
5775 rStream
.ReadBytes(&info
.verifier
.encryptedVerifierHash
, info
.verifier
.encryptedVerifierHashSize
);
5777 // check flags and algorithm IDs, required are AES128 and SHA-1
5778 if (!oox::getFlag(info
.header
.flags
, msfilter::ENCRYPTINFO_CRYPTOAPI
))
5781 if (oox::getFlag(info
.header
.flags
, msfilter::ENCRYPTINFO_AES
))
5784 if (info
.header
.algId
!= msfilter::ENCRYPT_ALGO_RC4
)
5787 // hash algorithm ID 0 defaults to SHA-1 too
5788 if (info
.header
.algIdHash
!= 0 && info
.header
.algIdHash
!= msfilter::ENCRYPT_HASH_SHA1
)
5794 ErrCode
SwWW8ImplReader::LoadThroughDecryption(WW8Glossary
*pGloss
)
5796 ErrCode nErrRet
= ERRCODE_NONE
;
5798 m_xWwFib
= pGloss
->GetFib();
5800 m_xWwFib
= std::make_shared
<WW8Fib
>(*m_pStrm
, m_nWantedVersion
);
5802 if (m_xWwFib
->m_nFibError
)
5803 nErrRet
= ERR_SWG_READ_ERROR
;
5805 rtl::Reference
<SotStorageStream
> xTableStream
, xDataStream
;
5808 nErrRet
= SetSubStreams(xTableStream
, xDataStream
);
5810 std::optional
<utl::TempFileFast
> oTempMain
;
5811 std::optional
<utl::TempFileFast
> oTempTable
;
5812 std::optional
<utl::TempFileFast
> oTempData
;
5813 SvStream
* pDecryptMain
= nullptr;
5814 SvStream
* pDecryptTable
= nullptr;
5815 SvStream
* pDecryptData
= nullptr;
5817 bool bDecrypt
= false;
5818 enum {RC4CryptoAPI
, RC4
, XOR
, Other
} eAlgo
= Other
;
5819 if (m_xWwFib
->m_fEncrypted
&& !nErrRet
)
5824 if (8 != m_xWwFib
->m_nVersion
)
5828 if (m_xWwFib
->m_nKey
!= 0)
5832 m_pTableStream
->Seek(0);
5833 sal_uInt32
nEncType(0);
5834 m_pTableStream
->ReadUInt32(nEncType
);
5835 if (nEncType
== msfilter::VERSION_INFO_1997_FORMAT
)
5837 else if (nEncType
== msfilter::VERSION_INFO_2007_FORMAT
|| nEncType
== msfilter::VERSION_INFO_2007_FORMAT_SP2
)
5838 eAlgo
= RC4CryptoAPI
;
5846 nErrRet
= ERRCODE_SVX_WRONGPASS
;
5847 SfxMedium
* pMedium
= m_pDocShell
->GetMedium();
5854 nErrRet
= ERRCODE_SVX_READ_FILTER_CRYPT
;
5858 msfilter::MSCodec_XorWord95 aCtx
;
5859 uno::Sequence
< beans::NamedValue
> aEncryptionData
= InitXorWord95Codec(aCtx
, *pMedium
, m_xWwFib
.get());
5861 // if initialization has failed the EncryptionData should be empty
5862 if (aEncryptionData
.hasElements() && aCtx
.VerifyKey(m_xWwFib
->m_nKey
, m_xWwFib
->m_nHash
))
5864 nErrRet
= ERRCODE_NONE
;
5865 pDecryptMain
= MakeTemp(oTempMain
);
5868 size_t nUnencryptedHdr
=
5869 (8 == m_xWwFib
->m_nVersion
) ? 0x44 : 0x34;
5870 std::unique_ptr
<sal_uInt8
[]> pIn(new sal_uInt8
[nUnencryptedHdr
]);
5871 nUnencryptedHdr
= m_pStrm
->ReadBytes(pIn
.get(), nUnencryptedHdr
);
5872 pDecryptMain
->WriteBytes(pIn
.get(), nUnencryptedHdr
);
5875 DecryptXOR(aCtx
, *m_pStrm
, *pDecryptMain
);
5877 if (!m_pTableStream
|| m_pTableStream
== m_pStrm
)
5878 m_pTableStream
= pDecryptMain
;
5881 pDecryptTable
= MakeTemp(oTempTable
);
5882 DecryptXOR(aCtx
, *m_pTableStream
, *pDecryptTable
);
5883 m_pTableStream
= pDecryptTable
;
5886 if (!m_pDataStream
|| m_pDataStream
== m_pStrm
)
5887 m_pDataStream
= pDecryptMain
;
5890 pDecryptData
= MakeTemp(oTempData
);
5891 DecryptXOR(aCtx
, *m_pDataStream
, *pDecryptData
);
5892 m_pDataStream
= pDecryptData
;
5895 pMedium
->GetItemSet().ClearItem( SID_PASSWORD
);
5896 pMedium
->GetItemSet().Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA
, uno::Any( aEncryptionData
) ) );
5903 std::unique_ptr
<msfilter::MSCodec97
> xCtx
;
5904 msfilter::RC4EncryptionInfo info
;
5905 bool bCouldReadHeaders
;
5909 xCtx
.reset(new msfilter::MSCodec_Std97
);
5910 assert(sizeof(info
.verifier
.encryptedVerifierHash
) >= RTL_DIGEST_LENGTH_MD5
);
5912 checkRead(*m_pTableStream
, info
.verifier
.salt
, sizeof(info
.verifier
.salt
)) &&
5913 checkRead(*m_pTableStream
, info
.verifier
.encryptedVerifier
, sizeof(info
.verifier
.encryptedVerifier
)) &&
5914 checkRead(*m_pTableStream
, info
.verifier
.encryptedVerifierHash
, RTL_DIGEST_LENGTH_MD5
);
5918 xCtx
.reset(new msfilter::MSCodec_CryptoAPI
);
5919 bCouldReadHeaders
= lclReadCryptoAPIHeader(info
, *m_pTableStream
);
5922 // if initialization has failed the EncryptionData should be empty
5923 uno::Sequence
< beans::NamedValue
> aEncryptionData
;
5924 if (bCouldReadHeaders
)
5925 aEncryptionData
= Init97Codec(*xCtx
, info
.verifier
.salt
, *pMedium
);
5927 nErrRet
= ERRCODE_SVX_READ_FILTER_CRYPT
;
5928 if (aEncryptionData
.hasElements() && xCtx
->VerifyKey(info
.verifier
.encryptedVerifier
,
5929 info
.verifier
.encryptedVerifierHash
))
5931 nErrRet
= ERRCODE_NONE
;
5933 pDecryptMain
= MakeTemp(oTempMain
);
5936 std::size_t nUnencryptedHdr
= 0x44;
5937 std::unique_ptr
<sal_uInt8
[]> pIn(new sal_uInt8
[nUnencryptedHdr
]);
5938 nUnencryptedHdr
= m_pStrm
->ReadBytes(pIn
.get(), nUnencryptedHdr
);
5940 DecryptRC4(*xCtx
, *m_pStrm
, *pDecryptMain
);
5942 pDecryptMain
->Seek(0);
5943 pDecryptMain
->WriteBytes(pIn
.get(), nUnencryptedHdr
);
5946 pDecryptTable
= MakeTemp(oTempTable
);
5947 DecryptRC4(*xCtx
, *m_pTableStream
, *pDecryptTable
);
5948 m_pTableStream
= pDecryptTable
;
5950 if (!m_pDataStream
|| m_pDataStream
== m_pStrm
)
5951 m_pDataStream
= pDecryptMain
;
5954 pDecryptData
= MakeTemp(oTempData
);
5955 DecryptRC4(*xCtx
, *m_pDataStream
, *pDecryptData
);
5956 m_pDataStream
= pDecryptData
;
5959 pMedium
->GetItemSet().ClearItem( SID_PASSWORD
);
5960 pMedium
->GetItemSet().Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA
, uno::Any( aEncryptionData
) ) );
5967 if (nErrRet
== ERRCODE_NONE
)
5969 m_pStrm
= pDecryptMain
;
5971 m_xWwFib
= std::make_shared
<WW8Fib
>(*m_pStrm
, m_nWantedVersion
);
5972 if (m_xWwFib
->m_nFibError
)
5973 nErrRet
= ERR_SWG_READ_ERROR
;
5978 nErrRet
= CoreLoad(pGloss
);
5988 void SwWW8ImplReader::SetOutlineStyles()
5990 // If we are inserted into a document then don't clobber existing outline
5992 sal_uInt16 nOutlineStyleListLevelWithAssignment
= 0;
5995 ww8::ParaStyles
aOutLined(sw::util::GetParaStyles(m_rDoc
));
5996 sw::util::SortByAssignedOutlineStyleListLevel(aOutLined
);
5997 ww8::ParaStyles::reverse_iterator aEnd
= aOutLined
.rend();
5998 for ( ww8::ParaStyles::reverse_iterator aIter
= aOutLined
.rbegin(); aIter
< aEnd
; ++aIter
)
6000 if ((*aIter
)->IsAssignedToListLevelOfOutlineStyle())
6001 nOutlineStyleListLevelWithAssignment
|= 1 << (*aIter
)->GetAssignedOutlineStyleLevel();
6007 // Check applied WW8 list styles at WW8 Built-In Heading Styles
6008 // - Choose the list style which occurs most often as the one which provides
6009 // the list level properties for the Outline Style.
6010 // - Populate temporary list of WW8 Built-In Heading Styles for further
6012 std::vector
<SwWW8StyInf
*> aWW8BuiltInHeadingStyles
;
6014 sal_uInt16 nStyle
= 0;
6015 std::map
<const SwNumRule
*, int> aWW8ListStyleCounts
;
6016 std::map
<const SwNumRule
*, bool> aPreventUseAsChapterNumbering
;
6017 for (SwWW8StyInf
& rSI
: m_vColl
)
6019 // Copy inherited numbering info since LO drops inheritance after ChapterNumbering
6020 // and only applies listLevel via style with the selected ChapterNumbering LFO.
6021 bool bReRegister
= false;
6022 if (rSI
.m_nBase
&& rSI
.m_nBase
< m_vColl
.size()
6023 && m_vColl
[rSI
.m_nBase
].HasWW8OutlineLevel())
6025 if (rSI
.m_nLFOIndex
== USHRT_MAX
)
6027 rSI
.m_nLFOIndex
= m_vColl
[rSI
.m_nBase
].m_nLFOIndex
;
6029 // When ANYTHING is wrong or strange, prohibit eligibility for ChapterNumbering.
6030 // A style never inherits numbering from Chapter Numbering.
6031 if (rSI
.m_nLFOIndex
!= USHRT_MAX
)
6033 const SwNumRule
* pNumRule
= m_vColl
[rSI
.m_nBase
].m_pOutlineNumrule
;
6035 aPreventUseAsChapterNumbering
[pNumRule
] = true;
6038 if (rSI
.m_nListLevel
== MAXLEVEL
)
6039 rSI
.m_nListLevel
= m_vColl
[rSI
.m_nBase
].m_nListLevel
;
6040 if (rSI
.mnWW8OutlineLevel
== MAXLEVEL
)
6041 rSI
.mnWW8OutlineLevel
= m_vColl
[rSI
.m_nBase
].mnWW8OutlineLevel
;
6045 // Undefined listLevel is treated as the first level with valid numbering rule.
6046 if (rSI
.m_nLFOIndex
< USHRT_MAX
&& rSI
.m_nListLevel
== MAXLEVEL
)
6048 rSI
.m_nListLevel
= 0;
6053 RegisterNumFormatOnStyle(nStyle
);
6055 ++nStyle
; // increment before the first "continue";
6057 if (!rSI
.m_bColl
|| !rSI
.IsWW8BuiltInHeadingStyle() || !rSI
.HasWW8OutlineLevel())
6062 // When ANYTHING is wrong or strange, prohibit eligibility for ChapterNumbering.
6063 if (rSI
.IsOutlineNumbered() && rSI
.m_nListLevel
!= rSI
.mnWW8OutlineLevel
)
6065 aPreventUseAsChapterNumbering
[rSI
.m_pOutlineNumrule
] = true;
6068 aWW8BuiltInHeadingStyles
.push_back(&rSI
);
6070 const SwNumRule
* pWW8ListStyle
= rSI
.GetOutlineNumrule();
6071 if (pWW8ListStyle
!= nullptr)
6073 std::map
<const SwNumRule
*, int>::iterator aCountIter
6074 = aWW8ListStyleCounts
.find(pWW8ListStyle
);
6075 if (aCountIter
== aWW8ListStyleCounts
.end())
6077 aWW8ListStyleCounts
[pWW8ListStyle
] = 1;
6081 ++(aCountIter
->second
);
6086 int nCurrentMaxCount
= 0;
6087 for (const auto& rEntry
: aWW8ListStyleCounts
)
6089 if (aPreventUseAsChapterNumbering
[rEntry
.first
])
6092 if (rEntry
.second
> nCurrentMaxCount
)
6094 nCurrentMaxCount
= rEntry
.second
;
6095 m_pChosenWW8OutlineStyle
= rEntry
.first
;
6100 // - set list level properties of Outline Style - ODF's list style applied
6101 // by default to headings
6102 // - assign corresponding Heading Paragraph Styles to the Outline Style
6103 // - If a heading Paragraph Styles is not applying the WW8 list style which
6104 // had been chosen as
6105 // the one which provides the list level properties for the Outline Style,
6106 // its assignment to
6107 // the Outline Style is removed. A potential applied WW8 list style is
6108 // assigned directly and
6109 // its default outline level is applied.
6110 SwNumRule
aOutlineRule(*m_rDoc
.GetOutlineNumRule());
6111 if (m_pChosenWW8OutlineStyle
)
6113 for (int i
= 0; i
< WW8ListManager::nMaxLevel
; ++i
)
6115 // Don't clobber existing outline levels.
6116 const sal_uInt16 nLevel
= 1 << i
;
6117 if (!(nOutlineStyleListLevelWithAssignment
& nLevel
))
6118 aOutlineRule
.Set(i
, m_pChosenWW8OutlineStyle
->Get(i
));
6122 for (const SwWW8StyInf
* pStyleInf
: aWW8BuiltInHeadingStyles
)
6124 const sal_uInt16 nOutlineStyleListLevelOfWW8BuiltInHeadingStyle
6125 = 1 << pStyleInf
->mnWW8OutlineLevel
;
6126 if (nOutlineStyleListLevelOfWW8BuiltInHeadingStyle
6127 & nOutlineStyleListLevelWithAssignment
)
6132 // in case that there are more styles on this level ignore them
6133 nOutlineStyleListLevelWithAssignment
6134 |= nOutlineStyleListLevelOfWW8BuiltInHeadingStyle
;
6136 SwTextFormatColl
* pTextFormatColl
= static_cast<SwTextFormatColl
*>(pStyleInf
->m_pFormat
);
6137 if (pStyleInf
->GetOutlineNumrule() != m_pChosenWW8OutlineStyle
6138 || (pStyleInf
->m_nListLevel
< WW8ListManager::nMaxLevel
6139 && pStyleInf
->mnWW8OutlineLevel
!= pStyleInf
->m_nListLevel
))
6141 // WW8 Built-In Heading Style does not apply the chosen one.
6142 // --> delete assignment to OutlineStyle, but keep its current
6144 pTextFormatColl
->DeleteAssignmentToListLevelOfOutlineStyle();
6145 // Apply existing WW8 list style a normal list style at the
6147 if (pStyleInf
->GetOutlineNumrule() != nullptr)
6149 pTextFormatColl
->SetFormatAttr(
6150 SwNumRuleItem(pStyleInf
->GetOutlineNumrule()->GetName()));
6152 // apply default outline level of WW8 Built-in Heading Style
6153 const sal_uInt8 nOutlineLevel
6154 = SwWW8StyInf::WW8OutlineLevelToOutlinelevel(
6155 pStyleInf
->mnWW8OutlineLevel
);
6156 pTextFormatColl
->SetFormatAttr(
6157 SfxUInt16Item(RES_PARATR_OUTLINELEVEL
, nOutlineLevel
));
6161 pTextFormatColl
->AssignToListLevelOfOutlineStyle(
6162 pStyleInf
->mnWW8OutlineLevel
);
6166 if (m_pChosenWW8OutlineStyle
)
6168 m_rDoc
.SetOutlineNumRule(aOutlineRule
);
6172 const OUString
* SwWW8ImplReader::GetAnnotationAuthor(sal_uInt16 nIdx
)
6174 if (!m_xAtnNames
&& m_xWwFib
->m_lcbGrpStAtnOwners
)
6176 // Determine authors: can be found in the TableStream
6177 m_xAtnNames
.emplace();
6178 SvStream
& rStrm
= *m_pTableStream
;
6180 auto nOldPos
= rStrm
.Tell();
6181 bool bValidPos
= checkSeek(rStrm
, m_xWwFib
->m_fcGrpStAtnOwners
);
6184 tools::Long nRead
= 0, nCount
= m_xWwFib
->m_lcbGrpStAtnOwners
;
6185 while (nRead
< nCount
&& rStrm
.good())
6189 m_xAtnNames
->push_back(read_uInt8_PascalString(rStrm
,
6190 RTL_TEXTENCODING_MS_1252
));
6191 nRead
+= m_xAtnNames
->rbegin()->getLength() + 1; // Length + sal_uInt8 count
6195 m_xAtnNames
->push_back(read_uInt16_PascalString(rStrm
));
6196 // Unicode: double the length + sal_uInt16 count
6197 nRead
+= (m_xAtnNames
->rbegin()->getLength() + 1)*2;
6201 rStrm
.Seek( nOldPos
);
6204 const OUString
*pRet
= nullptr;
6205 if (m_xAtnNames
&& nIdx
< m_xAtnNames
->size())
6206 pRet
= &((*m_xAtnNames
)[nIdx
]);
6210 void SwWW8ImplReader::GetSmartTagInfo(SwFltRDFMark
& rMark
)
6212 if (!m_pSmartTagData
&& m_xWwFib
->m_lcbFactoidData
)
6214 m_pSmartTagData
.reset(new WW8SmartTagData
);
6215 m_pSmartTagData
->Read(*m_pTableStream
, m_xWwFib
->m_fcFactoidData
, m_xWwFib
->m_lcbFactoidData
);
6218 if (!m_pSmartTagData
)
6221 // Check if the handle is a valid smart tag bookmark index.
6222 size_t nIndex
= rMark
.GetHandle();
6223 if (nIndex
>= m_pSmartTagData
->m_aPropBags
.size())
6226 // Check if the smart tag bookmark refers to a valid factoid type.
6227 const MSOPropertyBag
& rPropertyBag
= m_pSmartTagData
->m_aPropBags
[rMark
.GetHandle()];
6228 auto& rFactoidTypes
= m_pSmartTagData
->m_aPropBagStore
.m_aFactoidTypes
;
6229 auto itPropertyBag
= std::find_if(rFactoidTypes
.begin(), rFactoidTypes
.end(),
6230 [&rPropertyBag
](const MSOFactoidType
& rType
) { return rType
.m_nId
== rPropertyBag
.m_nId
; });
6231 if (itPropertyBag
== rFactoidTypes
.end())
6234 // Check if the factoid is an RDF one.
6235 const MSOFactoidType
& rFactoidType
= *itPropertyBag
;
6236 if (rFactoidType
.m_aUri
!= "http://www.w3.org/1999/02/22-rdf-syntax-ns#")
6239 // Finally put the relevant attributes to the mark.
6240 std::vector
< std::pair
<OUString
, OUString
> > aAttributes
;
6241 for (const MSOProperty
& rProperty
: rPropertyBag
.m_aProperties
)
6245 if (rProperty
.m_nKey
< m_pSmartTagData
->m_aPropBagStore
.m_aStringTable
.size())
6246 aKey
= m_pSmartTagData
->m_aPropBagStore
.m_aStringTable
[rProperty
.m_nKey
];
6247 if (rProperty
.m_nValue
< m_pSmartTagData
->m_aPropBagStore
.m_aStringTable
.size())
6248 aValue
= m_pSmartTagData
->m_aPropBagStore
.m_aStringTable
[rProperty
.m_nValue
];
6249 if (!aKey
.isEmpty() && !aValue
.isEmpty())
6250 aAttributes
.emplace_back(aKey
, aValue
);
6252 rMark
.SetAttributes(std::move(aAttributes
));
6255 ErrCode
SwWW8ImplReader::LoadDoc(WW8Glossary
*pGloss
)
6257 ErrCode nErrRet
= ERRCODE_NONE
;
6260 static constexpr OUString aNames
[ 13 ] = {
6261 u
"WinWord/WW"_ustr
, u
"WinWord/WW8"_ustr
, u
"WinWord/WWFT"_ustr
,
6262 u
"WinWord/WWFLX"_ustr
, u
"WinWord/WWFLY"_ustr
,
6263 u
"WinWord/WWF"_ustr
,
6264 u
"WinWord/WWFA0"_ustr
, u
"WinWord/WWFA1"_ustr
, u
"WinWord/WWFA2"_ustr
,
6265 u
"WinWord/WWFB0"_ustr
, u
"WinWord/WWFB1"_ustr
, u
"WinWord/WWFB2"_ustr
,
6266 u
"WinWord/RegardHindiDigits"_ustr
6268 sal_uInt64 aVal
[ 13 ];
6270 SwFilterOptions
aOpt( 13, aNames
, aVal
);
6272 m_nIniFlags
= aVal
[ 0 ];
6273 m_nIniFlags1
= aVal
[ 1 ];
6274 // Moves Flys by x twips to the right or left
6275 m_nIniFlyDx
= aVal
[ 3 ];
6276 m_nIniFlyDy
= aVal
[ 4 ];
6278 m_nFieldFlags
= aVal
[ 5 ];
6279 m_nFieldTagAlways
[0] = aVal
[ 6 ];
6280 m_nFieldTagAlways
[1] = aVal
[ 7 ];
6281 m_nFieldTagAlways
[2] = aVal
[ 8 ];
6282 m_nFieldTagBad
[0] = aVal
[ 9 ];
6283 m_nFieldTagBad
[1] = aVal
[ 10 ];
6284 m_nFieldTagBad
[2] = aVal
[ 11 ];
6285 m_bRegardHindiDigits
= aVal
[ 12 ] > 0;
6288 sal_uInt16
nMagic(0);
6289 m_pStrm
->ReadUInt16( nMagic
);
6291 // Remember: 6 means "6 OR 7", 7 means "JUST 7"
6292 switch (m_nWantedVersion
)
6297 0xa59b != nMagic
&& 0xa59c != nMagic
&&
6298 0xa5dc != nMagic
&& 0xa5db != nMagic
&&
6299 (nMagic
< 0xa697 || nMagic
> 0xa699)
6302 // Test for own 97 fake!
6303 if (m_pStg
&& 0xa5ec == nMagic
)
6305 sal_uInt64 nCurPos
= m_pStrm
->Tell();
6306 if (checkSeek(*m_pStrm
, nCurPos
+ 2))
6308 sal_uInt32
nfcMin(0);
6309 m_pStrm
->ReadUInt32( nfcMin
);
6310 if (0x300 != nfcMin
)
6311 nErrRet
= ERR_WW6_NO_WW6_FILE_ERR
;
6313 m_pStrm
->Seek( nCurPos
);
6316 nErrRet
= ERR_WW6_NO_WW6_FILE_ERR
;
6320 if (0xa5ec != nMagic
)
6321 nErrRet
= ERR_WW8_NO_WW8_FILE_ERR
;
6324 nErrRet
= ERR_WW8_NO_WW8_FILE_ERR
;
6325 OSL_ENSURE( false, "We forgot to encode nVersion!" );
6330 nErrRet
= LoadThroughDecryption(pGloss
);
6332 m_rDoc
.PropagateOutlineRule();
6337 extern "C" SAL_DLLPUBLIC_EXPORT Reader
* ImportDOC()
6339 return new WW8Reader
;
6344 class FontCacheGuard
6354 bool TestImportDOC(SvStream
&rStream
, const OUString
&rFltName
)
6356 FontCacheGuard aFontCacheGuard
;
6357 std::unique_ptr
<Reader
> xReader(ImportDOC());
6359 rtl::Reference
<SotStorage
> xStorage
;
6360 xReader
->m_pStream
= &rStream
;
6361 if (rFltName
!= "WW6")
6365 xStorage
.set(new SotStorage(rStream
));
6366 if (xStorage
->GetError())
6373 xReader
->m_pStorage
= xStorage
.get();
6375 xReader
->SetFltName(rFltName
);
6377 SwGlobals::ensure();
6379 SfxObjectShellLock
xDocSh(new SwDocShell(SfxObjectCreateMode::INTERNAL
));
6380 xDocSh
->DoInitNew();
6381 SwDoc
*pD
= static_cast<SwDocShell
*>((&xDocSh
))->GetDoc();
6383 SwPaM
aPaM(pD
->GetNodes().GetEndOfContent(), SwNodeOffset(-1));
6384 pD
->SetInReading(true);
6385 bool bRet
= xReader
->Read(*pD
, OUString(), aPaM
, OUString()) == ERRCODE_NONE
;
6386 pD
->SetInReading(false);
6391 extern "C" SAL_DLLPUBLIC_EXPORT
bool TestImportWW8(SvStream
&rStream
)
6393 return TestImportDOC(rStream
, u
"CWW8"_ustr
);
6396 extern "C" SAL_DLLPUBLIC_EXPORT
bool TestImportWW6(SvStream
&rStream
)
6398 return TestImportDOC(rStream
, u
"CWW6"_ustr
);
6401 extern "C" SAL_DLLPUBLIC_EXPORT
bool TestImportWW2(SvStream
&rStream
)
6403 return TestImportDOC(rStream
, u
"WW6"_ustr
);
6406 ErrCode
WW8Reader::OpenMainStream(rtl::Reference
<SotStorageStream
>& rRef
, sal_uInt16
& rBuffSize
)
6408 ErrCode nRet
= ERR_SWG_READ_ERROR
;
6409 OSL_ENSURE(m_pStorage
, "Where is my Storage?");
6410 rRef
= m_pStorage
->OpenSotStream( u
"WordDocument"_ustr
, StreamMode::READ
| StreamMode::SHARE_DENYALL
);
6414 if( ERRCODE_NONE
== rRef
->GetError() )
6416 sal_uInt16 nOld
= rRef
->GetBufferSize();
6417 rRef
->SetBufferSize( rBuffSize
);
6419 nRet
= ERRCODE_NONE
;
6422 nRet
= rRef
->GetError();
6427 static void lcl_getListOfStreams(SotStorage
* pStorage
, comphelper::SequenceAsHashMap
& aStreamsData
, std::u16string_view sPrefix
)
6429 SvStorageInfoList aElements
;
6430 pStorage
->FillInfoList(&aElements
);
6431 for (const auto & aElement
: aElements
)
6433 OUString sStreamFullName
= sPrefix
.size() ? OUString::Concat(sPrefix
) + "/" + aElement
.GetName() : aElement
.GetName();
6434 if (aElement
.IsStorage())
6436 rtl::Reference
<SotStorage
> xSubStorage
= pStorage
->OpenSotStorage(aElement
.GetName(), StreamMode::STD_READ
| StreamMode::SHARE_DENYALL
);
6437 lcl_getListOfStreams(xSubStorage
.get(), aStreamsData
, sStreamFullName
);
6442 rtl::Reference
<SotStorageStream
> rStream
= pStorage
->OpenSotStream(aElement
.GetName(), StreamMode::READ
| StreamMode::SHARE_DENYALL
);
6445 sal_Int32 nStreamSize
= rStream
->GetSize();
6446 css::uno::Sequence
< sal_Int8
> oData
;
6447 oData
.realloc(nStreamSize
);
6448 sal_Int32 nReadBytes
= rStream
->ReadBytes(oData
.getArray(), nStreamSize
);
6449 if (nStreamSize
== nReadBytes
)
6450 aStreamsData
[sStreamFullName
] <<= oData
;
6456 ErrCode
WW8Reader::DecryptDRMPackage()
6458 // We have DRM encrypted storage. We should try to decrypt it first, if we can
6459 uno::Sequence
< uno::Any
> aArguments
;
6460 const uno::Reference
<uno::XComponentContext
>& xComponentContext(comphelper::getProcessComponentContext());
6461 uno::Reference
< packages::XPackageEncryption
> xPackageEncryption(
6462 xComponentContext
->getServiceManager()->createInstanceWithArgumentsAndContext(
6463 u
"com.sun.star.comp.oox.crypto.DRMDataSpace"_ustr
, aArguments
, xComponentContext
), uno::UNO_QUERY
);
6465 if (!xPackageEncryption
.is())
6467 // We do not know how to decrypt this
6468 return ERRCODE_IO_ACCESSDENIED
;
6471 comphelper::SequenceAsHashMap aStreamsData
;
6472 lcl_getListOfStreams(m_pStorage
.get(), aStreamsData
, u
"");
6475 uno::Sequence
<beans::NamedValue
> aStreams
= aStreamsData
.getAsConstNamedValueList();
6476 if (!xPackageEncryption
->readEncryptionInfo(aStreams
))
6478 // We failed with decryption
6479 return ERRCODE_IO_ACCESSDENIED
;
6482 rtl::Reference
<SotStorageStream
> rContentStream
= m_pStorage
->OpenSotStream(u
"\011DRMContent"_ustr
, StreamMode::READ
| StreamMode::SHARE_DENYALL
);
6483 if (!rContentStream
.is())
6485 return ERRCODE_IO_NOTEXISTS
;
6488 mDecodedStream
= std::make_shared
<SvMemoryStream
>();
6490 uno::Reference
<io::XInputStream
> xInputStream(new utl::OSeekableInputStreamWrapper(rContentStream
.get(), false));
6491 uno::Reference
<io::XOutputStream
> xDecryptedStream(new utl::OSeekableOutputStreamWrapper(*mDecodedStream
));
6493 if (!xPackageEncryption
->decrypt(xInputStream
, xDecryptedStream
))
6495 // We failed with decryption
6496 return ERRCODE_IO_ACCESSDENIED
;
6499 mDecodedStream
->Seek(0);
6501 // Further reading is done from new document
6502 m_pStorage
= new SotStorage(*mDecodedStream
);
6504 // Set the media descriptor data
6505 uno::Sequence
<beans::NamedValue
> aEncryptionData
= xPackageEncryption
->createEncryptionData(u
""_ustr
);
6506 m_pMedium
->GetItemSet().Put(SfxUnoAnyItem(SID_ENCRYPTIONDATA
, uno::Any(aEncryptionData
)));
6508 catch (const std::exception
&)
6510 return ERRCODE_IO_ACCESSDENIED
;
6513 return ERRCODE_NONE
;
6516 ErrCodeMsg
WW8Reader::Read(SwDoc
&rDoc
, const OUString
& rBaseURL
, SwPaM
&rPaM
, const OUString
& /* FileName */)
6518 sal_uInt16 nOldBuffSize
= 32768;
6519 bool bNew
= !m_bInsertMode
; // New Doc (no inserting)
6521 rtl::Reference
<SotStorageStream
> refStrm
; // So that no one else can steal the Stream
6522 SvStream
* pIn
= m_pStream
;
6524 ErrCode nRet
= ERRCODE_NONE
;
6525 sal_uInt8 nVersion
= 8;
6527 const OUString sFltName
= GetFltName();
6528 if ( sFltName
=="WW6" )
6534 OSL_ENSURE(false, "WinWord 95 Reader-Read without Stream");
6535 nRet
= ERR_SWG_READ_ERROR
;
6540 if ( sFltName
=="CWW6" )
6542 else if ( sFltName
=="CWW7" )
6545 if( m_pStorage
.is() )
6547 // Check if we have special encrypted content
6548 rtl::Reference
<SotStorageStream
> rRef
= m_pStorage
->OpenSotStream(u
"\006DataSpaces/DataSpaceInfo/\011DRMDataSpace"_ustr
, StreamMode::READ
| StreamMode::SHARE_DENYALL
);
6551 nRet
= DecryptDRMPackage();
6553 nRet
= OpenMainStream(refStrm
, nOldBuffSize
);
6554 pIn
= refStrm
.get();
6558 OSL_ENSURE(false, "WinWord 95/97 Reader-Read without Storage");
6559 nRet
= ERR_SWG_READ_ERROR
;
6565 std::unique_ptr
<SwWW8ImplReader
> pRdr(new SwWW8ImplReader(nVersion
, m_pStorage
.get(), pIn
, rDoc
,
6566 rBaseURL
, bNew
, m_bSkipImages
, *rPaM
.GetPoint()));
6569 rPaM
.GetBound().nContent
.Assign(nullptr, 0);
6570 rPaM
.GetBound(false).nContent
.Assign(nullptr, 0);
6574 nRet
= pRdr
->LoadDoc();
6576 catch( const std::exception
& )
6578 nRet
= ERR_WW8_NO_WW8_FILE_ERR
;
6583 refStrm
->SetBufferSize( nOldBuffSize
);
6595 SwReaderType
WW8Reader::GetReaderType()
6597 return SwReaderType::Storage
| SwReaderType::Stream
;
6600 bool WW8Reader::HasGlossaries() const
6605 bool WW8Reader::ReadGlossaries(SwTextBlocks
& rBlocks
, bool bSaveRelFiles
) const
6609 WW8Reader
*pThis
= const_cast<WW8Reader
*>(this);
6611 sal_uInt16 nOldBuffSize
= 32768;
6612 rtl::Reference
<SotStorageStream
> refStrm
;
6613 if (!pThis
->OpenMainStream(refStrm
, nOldBuffSize
))
6615 WW8Glossary
aGloss( refStrm
, 8, m_pStorage
.get() );
6616 bRet
= aGloss
.Load( rBlocks
, bSaveRelFiles
);
6621 bool SwMSDffManager::GetOLEStorageName(sal_uInt32 nOLEId
, OUString
& rStorageName
,
6622 rtl::Reference
<SotStorage
>& rSrcStorage
, uno::Reference
< embed::XStorage
>& rDestStorage
) const
6626 sal_Int32 nPictureId
= 0;
6627 if (m_rReader
.m_pStg
)
6629 // Via the TextBox-PLCF we get the right char Start-End positions
6630 // We should then find the EmbeddedField and the corresponding Sprms
6632 // We only need the Sprm for the Picture Id.
6633 sal_uInt64 nOldPos
= m_rReader
.m_pStrm
->Tell();
6635 // #i32596# - consider return value of method
6636 // <rReader.GetTxbxTextSttEndCp(..)>. If it returns false, method
6637 // wasn't successful. Thus, continue in this case.
6638 // Note: Ask MM for initialization of <nStartCp> and <nEndCp>.
6639 // Note: Ask MM about assertions in method <rReader.GetTxbxTextSttEndCp(..)>.
6640 WW8_CP nStartCp
, nEndCp
;
6641 if ( m_rReader
.m_bDrawCpOValid
&& m_rReader
.GetTxbxTextSttEndCp(nStartCp
, nEndCp
,
6642 o3tl::narrowing
<sal_uInt16
>((nOLEId
>> 16) & 0xFFFF),
6643 o3tl::narrowing
<sal_uInt16
>(nOLEId
& 0xFFFF)) )
6645 WW8PLCFxSaveAll aSave
;
6646 m_rReader
.m_xPlcxMan
->SaveAllPLCFx( aSave
);
6648 nStartCp
+= m_rReader
.m_nDrawCpO
;
6649 nEndCp
+= m_rReader
.m_nDrawCpO
;
6650 WW8PLCFx_Cp_FKP
* pChp
= m_rReader
.m_xPlcxMan
->GetChpPLCF();
6651 wwSprmParser
aSprmParser(*m_rReader
.m_xWwFib
);
6652 while (nStartCp
<= nEndCp
&& !nPictureId
)
6654 if (!pChp
->SeekPos( nStartCp
))
6657 pChp
->GetSprms( &aDesc
);
6659 if (aDesc
.nSprmsLen
&& aDesc
.pMemPos
) // Attributes present
6661 auto nLen
= aDesc
.nSprmsLen
;
6662 const sal_uInt8
* pSprm
= aDesc
.pMemPos
;
6664 while (nLen
>= 2 && !nPictureId
)
6666 sal_uInt16 nId
= aSprmParser
.GetSprmId(pSprm
);
6667 sal_Int32 nSL
= aSprmParser
.GetSprmSize(nId
, pSprm
, nLen
);
6670 break; // Not enough Bytes left
6674 nPictureId
= SVBT32ToUInt32(pSprm
+
6675 aSprmParser
.DistanceToData(nId
));
6682 nStartCp
= aDesc
.nEndPos
;
6685 m_rReader
.m_xPlcxMan
->RestoreAllPLCFx( aSave
);
6688 m_rReader
.m_pStrm
->Seek( nOldPos
);
6694 rStorageName
+= OUString::number(nPictureId
);
6695 rSrcStorage
= m_rReader
.m_pStg
->OpenSotStorage(SL::aObjectPool
);
6696 if (!m_rReader
.m_pDocShell
)
6699 rDestStorage
= m_rReader
.m_pDocShell
->GetStorage();
6705 * When reading a single Box (which possibly is part of a group), we do
6706 * not yet have enough information to decide whether we need it as a TextField
6708 * So convert all of them as a precaution.
6709 * FIXME: Actually implement this!
6711 bool SwMSDffManager::ShapeHasText(sal_uLong
, sal_uLong
) const
6716 bool SwWW8ImplReader::InEqualOrHigherApo(int nLvl
) const
6720 // #i60827# - check size of <maApos> to assure that <maApos.begin() + nLvl> can be performed.
6721 if ( sal::static_int_cast
< sal_Int32
>(nLvl
) >= sal::static_int_cast
< sal_Int32
>(m_aApos
.size()) )
6725 auto aIter
= std::find(m_aApos
.begin() + nLvl
, m_aApos
.end(), true);
6726 return aIter
!= m_aApos
.end();
6729 bool SwWW8ImplReader::InEqualApo(int nLvl
) const
6731 // If we are in a table, see if an apo was inserted at the level below the table.
6734 if (nLvl
< 0 || o3tl::make_unsigned(nLvl
) >= m_aApos
.size())
6736 return m_aApos
[nLvl
];
6741 Position::Position(const SwPosition
&rPos
)
6742 : maPtNode(rPos
.GetNode()), mnPtContent(rPos
.GetContentIndex())
6746 Position::operator SwPosition() const
6748 return SwPosition(maPtNode
, maPtNode
.GetNode().GetContentNode(), mnPtContent
);
6752 SwMacroInfo::SwMacroInfo()
6753 : SdrObjUserData( SdrInventor::ScOrSwDraw
, SW_UD_IMAPDATA
)
6758 SwMacroInfo::~SwMacroInfo()
6762 std::unique_ptr
<SdrObjUserData
> SwMacroInfo::Clone( SdrObject
* /*pObj*/ ) const
6764 return std::unique_ptr
<SdrObjUserData
>(new SwMacroInfo( *this ));
6767 std::unique_ptr
<SfxItemSet
> SwWW8ImplReader::SetCurrentItemSet(std::unique_ptr
<SfxItemSet
> pItemSet
)
6769 std::unique_ptr
<SfxItemSet
> xRet(std::move(m_xCurrentItemSet
));
6770 m_xCurrentItemSet
= std::move(pItemSet
);
6774 void SwWW8ImplReader::NotifyMacroEventRead()
6776 if (m_bNotifyMacroEventRead
)
6778 if (SwDocShell
* pShell
= m_rDoc
.GetDocShell())
6780 uno::Reference
<frame::XModel
> const xModel(static_cast<SfxBaseModel
*>(pShell
->GetBaseModel().get()));
6781 comphelper::DocumentInfo::notifyMacroEventRead(xModel
);
6782 m_bNotifyMacroEventRead
= true;
6786 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */