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>
31 #include <i18nlangtag/languagetag.hxx>
33 #include <unotools/configmgr.hxx>
34 #include <unotools/ucbstreamhelper.hxx>
35 #include <unotools/streamwrap.hxx>
36 #include <rtl/random.h>
37 #include <rtl/ustring.hxx>
38 #include <rtl/ustrbuf.hxx>
40 #include <sfx2/docinf.hxx>
41 #include <sfx2/frame.hxx>
42 #include <sfx2/zoomitem.hxx>
43 #include <tools/urlobj.hxx>
44 #include <unotools/tempfile.hxx>
46 #include <comphelper/docpasswordrequest.hxx>
47 #include <comphelper/documentinfo.hxx>
48 #include <comphelper/propertysequence.hxx>
50 #include <editeng/outlobj.hxx>
51 #include <editeng/brushitem.hxx>
52 #include <editeng/formatbreakitem.hxx>
53 #include <editeng/tstpitem.hxx>
54 #include <editeng/ulspitem.hxx>
55 #include <editeng/langitem.hxx>
56 #include <editeng/opaqitem.hxx>
57 #include <editeng/charhiddenitem.hxx>
58 #include <editeng/fontitem.hxx>
59 #include <editeng/editeng.hxx>
60 #include <svx/svdoole2.hxx>
61 #include <svx/svdoashp.hxx>
62 #include <svx/svxerr.hxx>
63 #include <filter/msfilter/mscodec.hxx>
64 #include <svx/svdmodel.hxx>
65 #include <svx/xflclit.hxx>
66 #include <svx/sdasitm.hxx>
67 #include <svx/sdtagitm.hxx>
68 #include <svx/sdtcfitm.hxx>
69 #include <svx/sdtditm.hxx>
70 #include <svx/sdtmfitm.hxx>
71 #include <unotools/fltrcfg.hxx>
74 #include <fmtinfmt.hxx>
76 #include <fmthdft.hxx>
77 #include <fmtcntnt.hxx>
78 #include <fmtcnct.hxx>
79 #include <fmtanchr.hxx>
80 #include <fmtpdsc.hxx>
81 #include <ftninfo.hxx>
85 #include <pagedesc.hxx>
87 #include <poolfmt.hxx>
88 #include <fmtclbl.hxx>
89 #include <section.hxx>
91 #include <IDocumentFieldsAccess.hxx>
92 #include <IDocumentLayoutAccess.hxx>
93 #include <IDocumentMarkAccess.hxx>
94 #include <IDocumentStylePoolAccess.hxx>
95 #include <IDocumentExternalData.hxx>
96 #include <../../core/inc/DocumentRedlineManager.hxx>
97 #include <docufld.hxx>
98 #include <swfltopt.hxx>
100 #include <viewsh.hxx>
101 #include <shellres.hxx>
103 #include <swtable.hxx>
104 #include <fchrfmt.hxx>
105 #include <charfmt.hxx>
106 #include <fmtautofmt.hxx>
107 #include <IDocumentSettingAccess.hxx>
108 #include "sprmids.hxx"
110 #include "writerwordglue.hxx"
113 #include <editeng/editids.hrc>
114 #include <fmtflcnt.hxx>
115 #include <txatbase.hxx>
117 #include "ww8par2.hxx"
119 #include <com/sun/star/beans/PropertyAttribute.hpp>
120 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
121 #include <com/sun/star/document/XViewDataSupplier.hpp>
123 #include <svl/lngmisc.hxx>
124 #include <svl/itemiter.hxx>
125 #include <svl/whiter.hxx>
127 #include <comphelper/indexedpropertyvalues.hxx>
128 #include <comphelper/processfactory.hxx>
129 #include <basic/basmgr.hxx>
131 #include "ww8toolbar.hxx"
132 #include <o3tl/unit_conversion.hxx>
133 #include <o3tl/safeint.hxx>
134 #include <osl/file.hxx>
136 #include <breakit.hxx>
138 #include <sfx2/docfile.hxx>
140 #include "WW8Sttbf.hxx"
141 #include "WW8FibData.hxx"
142 #include <unordered_set>
145 using namespace ::com::sun::star
;
146 using namespace sw::util
;
147 using namespace sw::types
;
148 using namespace nsHdFtFlags
;
150 #include <com/sun/star/i18n/XBreakIterator.hpp>
151 #include <com/sun/star/i18n/ScriptType.hpp>
152 #include <unotools/pathoptions.hxx>
153 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
155 #include <com/sun/star/script/vba/XVBACompatibility.hpp>
156 #include <comphelper/sequenceashashmap.hxx>
157 #include <oox/ole/vbaproject.hxx>
158 #include <oox/ole/olestorage.hxx>
159 #include <comphelper/storagehelper.hxx>
160 #include <sfx2/DocumentMetadataAccess.hxx>
161 #include <comphelper/diagnose_ex.hxx>
163 static SwMacroInfo
* GetMacroInfo( SdrObject
* pObj
)
167 sal_uInt16 nCount
= pObj
->GetUserDataCount();
168 for( sal_uInt16 i
= 0; i
< nCount
; i
++ )
170 SdrObjUserData
* pData
= pObj
->GetUserData( i
);
171 if( pData
&& pData
->GetInventor() == SdrInventor::ScOrSwDraw
172 && pData
->GetId() == SW_UD_IMAPDATA
)
174 return dynamic_cast<SwMacroInfo
*>(pData
);
177 SwMacroInfo
* pData
= new SwMacroInfo
;
178 pObj
->AppendUserData(std::unique_ptr
<SdrObjUserData
>(pData
));
185 static void lclGetAbsPath(OUString
& rPath
, sal_uInt16 nLevel
, SwDocShell
const * pDocShell
)
187 OUStringBuffer aTmpStr
;
190 aTmpStr
.append("../");
193 if (!aTmpStr
.isEmpty())
194 aTmpStr
.append(rPath
);
198 if (!aTmpStr
.isEmpty())
200 bool bWasAbs
= false;
201 rPath
= pDocShell
->GetMedium()->GetURLObject().smartRel2Abs( aTmpStr
.makeStringAndClear(), bWasAbs
).GetMainURL( INetURLObject::DecodeMechanism::NONE
);
202 // full path as stored in SvxURLField must be encoded
208 void lclIgnoreUString32(SvStream
& rStrm
)
210 sal_uInt32
nChars(0);
211 rStrm
.ReadUInt32(nChars
);
213 rStrm
.SeekRel(nChars
);
217 void SwWW8ImplReader::ReadEmbeddedData(SvStream
& rStrm
, SwDocShell
const * pDocShell
, struct HyperLinksTable
& hlStr
)
220 // const sal_uInt16 WW8_ID_HLINK = 0x01B8;
221 constexpr sal_uInt32 WW8_HLINK_BODY
= 0x00000001; /// Contains file link or URL.
222 constexpr sal_uInt32 WW8_HLINK_ABS
= 0x00000002; /// Absolute path.
223 constexpr sal_uInt32 WW8_HLINK_DESCR
= 0x00000014; /// Description.
224 constexpr sal_uInt32 WW8_HLINK_MARK
= 0x00000008; /// Text mark.
225 constexpr sal_uInt32 WW8_HLINK_FRAME
= 0x00000080; /// Target frame.
226 constexpr sal_uInt32 WW8_HLINK_UNC
= 0x00000100; /// UNC path.
228 //sal_uInt8 maGuidStdLink[ 16 ] ={
229 // 0xD0, 0xC9, 0xEA, 0x79, 0xF9, 0xBA, 0xCE, 0x11, 0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B };
231 sal_uInt8
const aGuidUrlMoniker
[ 16 ] = {
232 0xE0, 0xC9, 0xEA, 0x79, 0xF9, 0xBA, 0xCE, 0x11, 0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B };
234 sal_uInt8
const aGuidFileMoniker
[ 16 ] = {
235 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 };
238 sal_uInt32
nFlags(0);
240 rStrm
.ReadBytes(aGuid
, 16);
242 rStrm
.ReadUInt32( nFlags
);
244 std::unique_ptr
< OUString
> xLongName
; // link / file name
245 std::unique_ptr
< OUString
> xShortName
; // 8.3-representation of file name
246 std::unique_ptr
< OUString
> xTextMark
; // text mark
248 // description (ignore)
249 if( ::get_flag( nFlags
, WW8_HLINK_DESCR
) )
250 lclIgnoreUString32( rStrm
);
253 if( ::get_flag( nFlags
, WW8_HLINK_FRAME
) )
255 hlStr
.tarFrame
= read_uInt32_lenPrefixed_uInt16s_ToOUString(rStrm
);
259 if( ::get_flag( nFlags
, WW8_HLINK_UNC
) )
261 // MS-OSHARED: An unsigned integer that specifies the number of Unicode characters in the
262 // string field, including the null-terminating character.
263 sal_uInt32
nStrLen(0);
264 rStrm
.ReadUInt32(nStrLen
);
267 xLongName
.reset(new OUString(read_uInt16s_ToOUString(rStrm
, nStrLen
- 1)));
268 rStrm
.SeekRel(sizeof(sal_Unicode
)); // skip null-byte at end
269 lclGetAbsPath( *xLongName
, 0 , pDocShell
);
273 else if( ::get_flag( nFlags
, WW8_HLINK_BODY
) )
275 rStrm
.ReadBytes(aGuid
, 16);
277 if( memcmp(aGuid
, aGuidFileMoniker
, 16) == 0 )
279 sal_uInt16 nLevel
= 0; // counter for level to climb down in path
280 rStrm
.ReadUInt16( nLevel
);
281 // MS-OSHARED: An unsigned integer that specifies the number of
282 // ANSI characters in ansiPath, including the terminating NULL character
283 sal_uInt32 nUnits
= 0;
284 rStrm
.ReadUInt32(nUnits
);
286 xShortName
.reset(new OUString
);
289 OString
sStr(read_uInt8s_ToOString(rStrm
, nUnits
- 1));
290 rStrm
.SeekRel(sizeof(sal_uInt8
)); // skip null-byte at end
291 xShortName
.reset(new OUString(sStr
.getStr(), sStr
.getLength(), GetCharSetFromLanguage()));
295 sal_uInt32
nStrLen(0);
296 rStrm
.ReadUInt32( nStrLen
);
300 rStrm
.ReadUInt32( nStrLen
);
303 // MS-OSHARED: This array MUST not include a terminating NULL character.
304 xLongName
.reset(new OUString(read_uInt16s_ToOUString(rStrm
, nStrLen
)));
305 lclGetAbsPath( *xLongName
, nLevel
, pDocShell
);
308 lclGetAbsPath( *xShortName
, nLevel
, pDocShell
);
310 else if( memcmp(aGuid
, aGuidUrlMoniker
, 16) == 0 )
312 // MS-OSHARED: An unsigned integer that specifies the size of this
313 // structure in bytes, excluding the size of the length field. The
314 // value of this field MUST be ... the byte size of the url
315 // field (including the terminating NULL character)
316 sal_uInt32
nStrLen(0);
317 rStrm
.ReadUInt32( nStrLen
);
320 xLongName
.reset(new OUString
);
323 xLongName
.reset(new OUString(read_uInt16s_ToOUString(rStrm
, nStrLen
- 1)));
324 rStrm
.SeekRel(sizeof(sal_Unicode
)); // skip null-byte at end
326 if( !::get_flag( nFlags
, WW8_HLINK_ABS
) )
327 lclGetAbsPath( *xLongName
, 0 ,pDocShell
);
331 SAL_INFO("sw.ww8", "WW8Hyperlink::ReadEmbeddedData - unknown content GUID");
336 if( ::get_flag( nFlags
, WW8_HLINK_MARK
) )
338 xTextMark
.reset(new OUString(read_uInt32_lenPrefixed_uInt16s_ToOUString(rStrm
)));
341 if (!xLongName
&& xShortName
)
342 xLongName
.reset(new OUString(*xShortName
));
343 else if (!xLongName
&& xTextMark
)
344 xLongName
.reset( new OUString
);
350 if (xLongName
->isEmpty())
351 *xTextMark
= xTextMark
->replace('!', '.');
352 *xLongName
+= "#" + *xTextMark
;
354 hlStr
.hLinkAddr
= *xLongName
;
360 class BasicProjImportHelper
362 SwDocShell
& mrDocShell
;
363 uno::Reference
< uno::XComponentContext
> mxCtx
;
365 explicit BasicProjImportHelper( SwDocShell
& rShell
) : mrDocShell( rShell
),
366 mxCtx(comphelper::getProcessComponentContext())
369 bool import( const uno::Reference
< io::XInputStream
>& rxIn
);
370 OUString
getProjectName() const;
375 bool BasicProjImportHelper::import( const uno::Reference
< io::XInputStream
>& rxIn
)
380 oox::ole::OleStorage
root( mxCtx
, rxIn
, false );
381 oox::StorageRef vbaStg
= root
.openSubStorage( "Macros" , false );
384 oox::ole::VbaProject
aVbaPrj( mxCtx
, mrDocShell
.GetModel(), u
"Writer" );
385 bRet
= aVbaPrj
.importVbaProject( *vbaStg
);
388 catch( const uno::Exception
& )
395 OUString
BasicProjImportHelper::getProjectName() const
397 OUString
sProjName( "Standard" );
398 uno::Reference
< beans::XPropertySet
> xProps( mrDocShell
.GetModel(), uno::UNO_QUERY
);
403 uno::Reference
< script::vba::XVBACompatibility
> xVBA( xProps
->getPropertyValue( "BasicLibraries" ), uno::UNO_QUERY_THROW
);
404 sProjName
= xVBA
->getProjectName();
407 catch( const uno::Exception
& )
416 class Sttb
: public TBBase
422 SBBItem() : cchData(0){}
424 sal_uInt16 m_fExtend
;
426 sal_uInt16 m_cbExtra
;
428 std::vector
< SBBItem
> m_dataItems
;
430 Sttb(Sttb
const&) = delete;
431 Sttb
& operator=(Sttb
const&) = delete;
436 bool Read(SvStream
&rS
) override
;
437 OUString
getStringAtIndex( sal_uInt32
);
449 bool Sttb::Read( SvStream
& rS
)
451 SAL_INFO("sw.ww8", "stream pos " << rS
.Tell());
453 rS
.ReadUInt16( m_fExtend
).ReadUInt16( m_cData
).ReadUInt16( m_cbExtra
);
456 //if they are all going to be empty strings, how many could there be
457 const size_t nMaxPossibleRecords
= rS
.remainingSize() / sizeof(sal_uInt16
);
458 if (m_cData
> nMaxPossibleRecords
)
460 for ( sal_Int32 index
= 0; index
< m_cData
; ++index
)
463 rS
.ReadUInt16( aItem
.cchData
);
464 aItem
.data
= read_uInt16s_ToOUString(rS
, aItem
.cchData
);
465 m_dataItems
.push_back( aItem
);
472 Sttb::getStringAtIndex( sal_uInt32 index
)
475 if ( index
< m_dataItems
.size() )
476 aRet
= m_dataItems
[ index
].data
;
481 SwMSDffManager::SwMSDffManager( SwWW8ImplReader
& rRdr
, bool bSkipImages
)
482 : SvxMSDffManager(*rRdr
.m_pTableStream
, rRdr
.GetBaseURL(), rRdr
.m_xWwFib
->m_fcDggInfo
,
483 rRdr
.m_pDataStream
, nullptr, 0, COL_WHITE
, rRdr
.m_pStrm
, bSkipImages
),
484 m_rReader(rRdr
), m_pFallbackStream(nullptr)
486 SetSvxMSDffSettings( GetSvxMSDffSettings() );
487 nSvxMSDffOLEConvFlags
= SwMSDffManager::GetFilterFlags();
490 sal_uInt32
SwMSDffManager::GetFilterFlags()
492 sal_uInt32
nFlags(0);
493 const SvtFilterOptions
& rOpt
= SvtFilterOptions::Get();
494 if (rOpt
.IsMathType2Math())
495 nFlags
|= OLE_MATHTYPE_2_STARMATH
;
496 if (rOpt
.IsExcel2Calc())
497 nFlags
|= OLE_EXCEL_2_STARCALC
;
498 if (rOpt
.IsPowerPoint2Impress())
499 nFlags
|= OLE_POWERPOINT_2_STARIMPRESS
;
500 if (rOpt
.IsWinWord2Writer())
501 nFlags
|= OLE_WINWORD_2_STARWRITER
;
506 * I would like to override the default OLE importing to add a test
507 * and conversion of OCX controls from their native OLE type into our
508 * native nonOLE Form Control Objects.
510 // #i32596# - consider new parameter <_nCalledByGroup>
511 rtl::Reference
<SdrObject
> SwMSDffManager::ImportOLE( sal_uInt32 nOLEId
,
513 const tools::Rectangle
& rBoundRect
,
514 const tools::Rectangle
& rVisArea
,
515 const int _nCalledByGroup
) const
517 // #i32596# - no import of OLE object, if it's inside a group.
518 // NOTE: This can be undone, if grouping of Writer fly frames is possible or
519 // if drawing OLE objects are allowed in Writer.
520 if ( _nCalledByGroup
> 0 )
525 rtl::Reference
<SdrObject
> pRet
;
526 OUString sStorageName
;
527 tools::SvRef
<SotStorage
> xSrcStg
;
528 uno::Reference
< embed::XStorage
> xDstStg
;
529 if( GetOLEStorageName( nOLEId
, sStorageName
, xSrcStg
, xDstStg
))
531 tools::SvRef
<SotStorage
> xSrc
= xSrcStg
->OpenSotStorage( sStorageName
);
532 OSL_ENSURE(m_rReader
.m_xFormImpl
, "No Form Implementation!");
533 css::uno::Reference
< css::drawing::XShape
> xShape
;
534 if ( (!(m_rReader
.m_bIsHeader
|| m_rReader
.m_bIsFooter
)) &&
535 m_rReader
.m_xFormImpl
->ReadOCXStream(xSrc
,&xShape
,true))
537 pRet
= SdrObject::getSdrObjectFromXShape(xShape
);
541 ErrCode nError
= ERRCODE_NONE
;
542 pRet
= CreateSdrOLEFromStorage(
552 nSvxMSDffOLEConvFlags
,
553 css::embed::Aspects::MSOLE_CONTENT
,
554 m_rReader
.GetBaseURL());
560 void SwMSDffManager::DisableFallbackStream()
562 OSL_ENSURE(!m_pFallbackStream
,
563 "if you're recursive, you're broken");
564 m_pFallbackStream
= pStData2
;
565 m_aOldEscherBlipCache
= aEscherBlipCache
;
566 aEscherBlipCache
.clear();
570 void SwMSDffManager::EnableFallbackStream()
572 pStData2
= m_pFallbackStream
;
573 aEscherBlipCache
= m_aOldEscherBlipCache
;
574 m_aOldEscherBlipCache
.clear();
575 m_pFallbackStream
= nullptr;
578 sal_uInt16
SwWW8ImplReader::GetToggleAttrFlags() const
580 return m_xCtrlStck
? m_xCtrlStck
->GetToggleAttrFlags() : 0;
583 sal_uInt16
SwWW8ImplReader::GetToggleBiDiAttrFlags() const
585 return m_xCtrlStck
? m_xCtrlStck
->GetToggleBiDiAttrFlags() : 0;
588 void SwWW8ImplReader::SetToggleAttrFlags(sal_uInt16 nFlags
)
591 m_xCtrlStck
->SetToggleAttrFlags(nFlags
);
594 void SwWW8ImplReader::SetToggleBiDiAttrFlags(sal_uInt16 nFlags
)
597 m_xCtrlStck
->SetToggleBiDiAttrFlags(nFlags
);
600 rtl::Reference
<SdrObject
> SwMSDffManager::ProcessObj(SvStream
& rSt
,
601 DffObjData
& rObjData
,
602 SvxMSDffClientData
& rData
,
603 tools::Rectangle
& rTextRect
,
607 rtl::Reference
<SdrObject
> pObj
= pObj1
;
608 if( !rTextRect
.IsEmpty() )
610 SvxMSDffImportData
& rImportData
= static_cast<SvxMSDffImportData
&>(rData
);
611 std::unique_ptr
<SvxMSDffImportRec
> pImpRec(new SvxMSDffImportRec
);
613 // fill Import Record with data
614 pImpRec
->nShapeId
= rObjData
.nShapeId
;
615 pImpRec
->eShapeType
= rObjData
.eShapeType
;
617 rObjData
.bClientAnchor
= maShapeRecords
.SeekToContent( rSt
,
618 DFF_msofbtClientAnchor
,
619 SEEK_FROM_CURRENT_AND_RESTART
);
620 if( rObjData
.bClientAnchor
)
621 ProcessClientAnchor( rSt
,
622 maShapeRecords
.Current()->nRecLen
,
623 pImpRec
->pClientAnchorBuffer
, pImpRec
->nClientAnchorLen
);
625 rObjData
.bClientData
= maShapeRecords
.SeekToContent( rSt
,
626 DFF_msofbtClientData
,
627 SEEK_FROM_CURRENT_AND_RESTART
);
628 if( rObjData
.bClientData
)
629 ProcessClientData( rSt
,
630 maShapeRecords
.Current()->nRecLen
,
631 pImpRec
->pClientDataBuffer
, pImpRec
->nClientDataLen
);
633 pImpRec
->nGroupShapeBooleanProperties
= 0;
635 if( maShapeRecords
.SeekToContent( rSt
,
637 SEEK_FROM_CURRENT_AND_RESTART
)
638 && maShapeRecords
.Current()->nRecLen
)
640 sal_uInt32 nBytesLeft
= maShapeRecords
.Current()->nRecLen
;
641 auto nAvailableBytes
= rSt
.remainingSize();
642 if (nBytesLeft
> nAvailableBytes
)
644 SAL_WARN("sw.ww8", "Document claimed to have shape record of " << nBytesLeft
<< " bytes, but only " << nAvailableBytes
<< " available");
645 nBytesLeft
= nAvailableBytes
;
647 while( 5 < nBytesLeft
)
650 rSt
.ReadUInt16(nPID
);
651 sal_uInt32
nUDData(0);
652 rSt
.ReadUInt32(nUDData
);
657 case 0x038F: pImpRec
->nXAlign
= nUDData
; break;
659 pImpRec
->nXRelTo
= nUDData
;
661 case 0x0391: pImpRec
->nYAlign
= nUDData
; break;
663 pImpRec
->nYRelTo
= nUDData
;
665 case 0x03BF: pImpRec
->nGroupShapeBooleanProperties
= nUDData
; break;
667 // This seems to correspond to o:hrpct from .docx (even including
668 // the difference that it's in 0.1% even though the .docx spec
670 pImpRec
->relativeHorizontalWidth
= nUDData
;
673 // And this is really just a guess, but a mere presence of this
674 // flag makes a horizontal rule be as wide as the page (unless
675 // overridden by something), so it probably matches o:hr from .docx.
676 pImpRec
->isHorizontalRule
= true;
683 // Text Frame also Title or Outline
684 sal_uInt32 nTextId
= GetPropertyValue( DFF_Prop_lTxid
, 0 );
687 SfxItemSet
aSet( pSdrModel
->GetItemPool() );
689 // Originally anything that as a mso_sptTextBox was created as a
690 // textbox, this was changed to be created as a simple
691 // rect to keep impress happy. For the rest of us we'd like to turn
692 // it back into a textbox again.
693 bool bIsSimpleDrawingTextBox
= (pImpRec
->eShapeType
== mso_sptTextBox
);
694 if (!bIsSimpleDrawingTextBox
)
697 // a) it's a simple text object or
698 // b) it's a rectangle with text and square wrapping.
699 bIsSimpleDrawingTextBox
=
701 (pImpRec
->eShapeType
== mso_sptTextSimple
) ||
703 (pImpRec
->eShapeType
== mso_sptRectangle
)
704 && ShapeHasText(pImpRec
->nShapeId
, rObjData
.rSpHd
.GetRecBegFilePos() )
709 // Distance of Textbox to its surrounding Autoshape
710 sal_Int32 nTextLeft
= GetPropertyValue( DFF_Prop_dxTextLeft
, 91440);
711 sal_Int32 nTextRight
= GetPropertyValue( DFF_Prop_dxTextRight
, 91440 );
712 sal_Int32 nTextTop
= GetPropertyValue( DFF_Prop_dyTextTop
, 45720 );
713 sal_Int32 nTextBottom
= GetPropertyValue( DFF_Prop_dyTextBottom
, 45720 );
715 ScaleEmu( nTextLeft
);
716 ScaleEmu( nTextRight
);
717 ScaleEmu( nTextTop
);
718 ScaleEmu( nTextBottom
);
720 Degree100 nTextRotationAngle
;
721 bool bVerticalText
= false;
722 if ( IsProperty( DFF_Prop_txflTextFlow
) )
724 MSO_TextFlow eTextFlow
= static_cast<MSO_TextFlow
>(GetPropertyValue(
725 DFF_Prop_txflTextFlow
, 0) & 0xFFFF);
729 nTextRotationAngle
= 9000_deg100
;
733 nTextRotationAngle
= 27000_deg100
;
736 bVerticalText
= true;
739 bVerticalText
= true;
740 nTextRotationAngle
= 9000_deg100
;
748 if (nTextRotationAngle
)
750 if (nTextRotationAngle
== 9000_deg100
)
752 tools::Long nWidth
= rTextRect
.GetWidth();
753 rTextRect
.SetRight( rTextRect
.Left() + rTextRect
.GetHeight() );
754 rTextRect
.SetBottom( rTextRect
.Top() + nWidth
);
756 sal_Int32 nOldTextLeft
= nTextLeft
;
757 sal_Int32 nOldTextRight
= nTextRight
;
758 sal_Int32 nOldTextTop
= nTextTop
;
759 sal_Int32 nOldTextBottom
= nTextBottom
;
761 nTextLeft
= nOldTextBottom
;
762 nTextRight
= nOldTextTop
;
763 nTextTop
= nOldTextLeft
;
764 nTextBottom
= nOldTextRight
;
766 else if (nTextRotationAngle
== 27000_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
= nOldTextTop
;
778 nTextRight
= nOldTextBottom
;
779 nTextTop
= nOldTextRight
;
780 nTextBottom
= nOldTextLeft
;
784 if (bIsSimpleDrawingTextBox
)
786 pObj
= new SdrRectObj(
792 // The vertical paragraph justification are contained within the
793 // BoundRect so calculate it here
794 tools::Rectangle
aNewRect(rTextRect
);
795 aNewRect
.AdjustBottom( -(nTextTop
+ nTextBottom
) );
796 aNewRect
.AdjustRight( -(nTextLeft
+ nTextRight
) );
798 // Only if it's a simple Textbox, Writer can replace the Object
799 // with a Frame, else
800 if( bIsSimpleDrawingTextBox
)
802 std::shared_ptr
<SvxMSDffShapeInfo
> const xTmpRec
=
803 std::make_shared
<SvxMSDffShapeInfo
>(0, pImpRec
->nShapeId
);
805 SvxMSDffShapeInfos_ById::const_iterator
const it
=
806 GetShapeInfos()->find(xTmpRec
);
807 if (it
!= GetShapeInfos()->end())
809 SvxMSDffShapeInfo
& rInfo
= **it
;
810 pImpRec
->bReplaceByFly
= rInfo
.bReplaceByFly
;
813 ApplyAttributes(rSt
, aSet
, rObjData
);
816 if (GetPropertyValue(DFF_Prop_FitTextToShape
, 0) & 2)
818 aSet
.Put( makeSdrTextAutoGrowHeightItem( true ) );
819 aSet
.Put( makeSdrTextMinFrameHeightItem(
820 aNewRect
.Bottom() - aNewRect
.Top() ) );
821 aSet
.Put( makeSdrTextMinFrameWidthItem(
822 aNewRect
.Right() - aNewRect
.Left() ) );
826 aSet
.Put( makeSdrTextAutoGrowHeightItem( false ) );
827 aSet
.Put( makeSdrTextAutoGrowWidthItem( false ) );
830 switch ( static_cast<MSO_WrapMode
>(GetPropertyValue( DFF_Prop_WrapText
, mso_wrapSquare
)) )
833 aSet
.Put( makeSdrTextAutoGrowWidthItem( true ) );
834 pImpRec
->bAutoWidth
= true;
836 case mso_wrapByPoints
:
837 aSet
.Put( makeSdrTextContourFrameItem( true ) );
843 // Set distances on Textbox's margins
844 aSet
.Put( makeSdrTextLeftDistItem( nTextLeft
) );
845 aSet
.Put( makeSdrTextRightDistItem( nTextRight
) );
846 aSet
.Put( makeSdrTextUpperDistItem( nTextTop
) );
847 aSet
.Put( makeSdrTextLowerDistItem( nTextBottom
) );
848 pImpRec
->nDxTextLeft
= nTextLeft
;
849 pImpRec
->nDyTextTop
= nTextTop
;
850 pImpRec
->nDxTextRight
= nTextRight
;
851 pImpRec
->nDyTextBottom
= nTextBottom
;
853 // Taking the correct default (which is mso_anchorTop)
854 sal_uInt32 eTextAnchor
=
855 GetPropertyValue( DFF_Prop_anchorText
, mso_anchorTop
);
857 SdrTextVertAdjust eTVA
= bVerticalText
858 ? SDRTEXTVERTADJUST_BLOCK
859 : SDRTEXTVERTADJUST_CENTER
;
860 SdrTextHorzAdjust eTHA
= bVerticalText
861 ? SDRTEXTHORZADJUST_CENTER
862 : SDRTEXTHORZADJUST_BLOCK
;
864 switch( eTextAnchor
)
869 eTHA
= SDRTEXTHORZADJUST_RIGHT
;
871 eTVA
= SDRTEXTVERTADJUST_TOP
;
874 case mso_anchorTopCentered
:
877 eTHA
= SDRTEXTHORZADJUST_RIGHT
;
879 eTVA
= SDRTEXTVERTADJUST_TOP
;
882 case mso_anchorMiddle
:
884 case mso_anchorMiddleCentered
:
886 case mso_anchorBottom
:
889 eTHA
= SDRTEXTHORZADJUST_LEFT
;
891 eTVA
= SDRTEXTVERTADJUST_BOTTOM
;
894 case mso_anchorBottomCentered
:
897 eTHA
= SDRTEXTHORZADJUST_LEFT
;
899 eTVA
= SDRTEXTVERTADJUST_BOTTOM
;
906 aSet
.Put( SdrTextVertAdjustItem( eTVA
) );
907 aSet
.Put( SdrTextHorzAdjustItem( eTHA
) );
911 pObj
->SetMergedItemSet(aSet
);
915 SdrTextObj
*pTextObj
= DynCastSdrTextObj(pObj
.get());
917 pTextObj
->SetVerticalWriting(true);
920 if ( bIsSimpleDrawingTextBox
)
922 if ( nTextRotationAngle
)
924 tools::Long nMinWH
= rTextRect
.GetWidth() < rTextRect
.GetHeight() ?
925 rTextRect
.GetWidth() : rTextRect
.GetHeight();
927 Point
aPivot(rTextRect
.TopLeft());
928 aPivot
.AdjustX(nMinWH
);
929 aPivot
.AdjustY(nMinWH
);
930 pObj
->NbcRotate(aPivot
, nTextRotationAngle
);
934 if ( ( ( rObjData
.nSpFlags
& ShapeFlag::FlipV
) || mnFix16Angle
|| nTextRotationAngle
) && dynamic_cast< SdrObjCustomShape
* >( pObj
.get() ) )
936 SdrObjCustomShape
* pCustomShape
= dynamic_cast< SdrObjCustomShape
* >( pObj
.get() );
939 double fExtraTextRotation
= 0.0;
940 if ( mnFix16Angle
&& !( GetPropertyValue( DFF_Prop_FitTextToShape
, 0 ) & 4 ) )
941 { // text is already rotated, we have to take back the object rotation if DFF_Prop_RotateText is false
942 fExtraTextRotation
= -mnFix16Angle
.get();
944 if ( rObjData
.nSpFlags
& ShapeFlag::FlipV
) // sj: in ppt the text is flipped, whereas in word the text
945 { // remains unchanged, so we have to take back the flipping here
946 fExtraTextRotation
+= 18000.0; // because our core will flip text if the shape is flipped.
948 fExtraTextRotation
+= nTextRotationAngle
.get();
949 if ( !::basegfx::fTools::equalZero( fExtraTextRotation
) )
951 fExtraTextRotation
/= 100.0;
952 SdrCustomShapeGeometryItem
aGeometryItem( pCustomShape
->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY
) );
953 css::beans::PropertyValue aPropVal
;
954 aPropVal
.Name
= "TextRotateAngle";
955 aPropVal
.Value
<<= fExtraTextRotation
;
956 aGeometryItem
.SetPropertyValue( aPropVal
);
957 pCustomShape
->SetMergedItem( aGeometryItem
);
961 else if ( mnFix16Angle
)
963 // rotate text with shape ?
964 pObj
->NbcRotate( rObjData
.aBoundRect
.Center(), mnFix16Angle
);
970 // simple rectangular objects are ignored by ImportObj() :-(
971 // this is OK for Draw but not for Calc and Writer
972 // cause here these objects have a default border
973 pObj
= new SdrRectObj(
977 SfxItemSet
aSet( pSdrModel
->GetItemPool() );
978 ApplyAttributes( rSt
, aSet
, rObjData
);
980 SfxItemState eState
= aSet
.GetItemState( XATTR_FILLCOLOR
, false );
981 if( SfxItemState::DEFAULT
== eState
)
982 aSet
.Put( XFillColorItem( OUString(), mnDefaultColor
) );
983 pObj
->SetMergedItemSet(aSet
);
986 // Means that fBehindDocument is set
987 if (GetPropertyValue(DFF_Prop_fPrint
, 0) & 0x20)
988 pImpRec
->bDrawHell
= true;
990 pImpRec
->bDrawHell
= false;
991 if (GetPropertyValue(DFF_Prop_fPrint
, 0) & 0x02)
992 pImpRec
->bHidden
= true;
993 pImpRec
->nNextShapeId
= GetPropertyValue( DFF_Prop_hspNext
, 0 );
997 pImpRec
->aTextId
.nTxBxS
= o3tl::narrowing
<sal_uInt16
>( nTextId
>> 16 );
998 pImpRec
->aTextId
.nSequence
= o3tl::narrowing
<sal_uInt16
>(nTextId
);
1001 pImpRec
->nDxWrapDistLeft
= o3tl::convert(GetPropertyValue(DFF_Prop_dxWrapDistLeft
, 114935),
1002 o3tl::Length::emu
, o3tl::Length::twip
);
1003 pImpRec
->nDyWrapDistTop
= o3tl::convert(GetPropertyValue(DFF_Prop_dyWrapDistTop
, 0),
1004 o3tl::Length::emu
, o3tl::Length::twip
);
1005 pImpRec
->nDxWrapDistRight
1006 = o3tl::convert(GetPropertyValue(DFF_Prop_dxWrapDistRight
, 114935), o3tl::Length::emu
,
1007 o3tl::Length::twip
);
1008 pImpRec
->nDyWrapDistBottom
= o3tl::convert(GetPropertyValue(DFF_Prop_dyWrapDistBottom
, 0),
1009 o3tl::Length::emu
, o3tl::Length::twip
);
1010 // 16.16 fraction times total image width or height, as appropriate.
1012 if (SeekToContent(DFF_Prop_pWrapPolygonVertices
, rSt
))
1014 pImpRec
->pWrapPolygon
.reset();
1016 sal_uInt16
nNumElemVert(0), nNumElemMemVert(0), nElemSizeVert(0);
1017 rSt
.ReadUInt16( nNumElemVert
).ReadUInt16( nNumElemMemVert
).ReadUInt16( nElemSizeVert
);
1019 if (nNumElemVert
&& (nElemSizeVert
== 8 || nElemSizeVert
== 4))
1021 //check if there is enough data in the file to make the
1023 // coverity[tainted_data : FALSE] - nElemSizeVert is either 8 or 4 so it has been sanitized
1024 bOk
= rSt
.remainingSize() / nElemSizeVert
>= nNumElemVert
;
1028 pImpRec
->pWrapPolygon
= tools::Polygon(nNumElemVert
);
1029 for (sal_uInt16 i
= 0; i
< nNumElemVert
; ++i
)
1031 sal_Int32
nX(0), nY(0);
1032 if (nElemSizeVert
== 8)
1033 rSt
.ReadInt32( nX
).ReadInt32( nY
);
1036 sal_Int16
nSmallX(0), nSmallY(0);
1037 rSt
.ReadInt16( nSmallX
).ReadInt16( nSmallY
);
1041 (*(pImpRec
->pWrapPolygon
))[i
].setX( nX
);
1042 (*(pImpRec
->pWrapPolygon
))[i
].setY( nY
);
1047 pImpRec
->nCropFromTop
= GetPropertyValue(
1048 DFF_Prop_cropFromTop
, 0 );
1049 pImpRec
->nCropFromBottom
= GetPropertyValue(
1050 DFF_Prop_cropFromBottom
, 0 );
1051 pImpRec
->nCropFromLeft
= GetPropertyValue(
1052 DFF_Prop_cropFromLeft
, 0 );
1053 pImpRec
->nCropFromRight
= GetPropertyValue(
1054 DFF_Prop_cropFromRight
, 0 );
1056 sal_uInt32 nLineFlags
= GetPropertyValue( DFF_Prop_fNoLineDrawDash
, 0 );
1058 if ( !IsHardAttribute( DFF_Prop_fLine
) &&
1059 pImpRec
->eShapeType
== mso_sptPictureFrame
)
1061 nLineFlags
&= ~0x08;
1064 pImpRec
->eLineStyle
= (nLineFlags
& 8)
1065 ? static_cast<MSO_LineStyle
>(GetPropertyValue(
1068 : MSO_LineStyle(USHRT_MAX
);
1069 pImpRec
->eLineDashing
= static_cast<MSO_LineDashing
>(GetPropertyValue(
1070 DFF_Prop_lineDashing
, mso_lineSolid
));
1072 pImpRec
->nFlags
= rObjData
.nSpFlags
;
1074 if( pImpRec
->nShapeId
)
1076 auto nShapeId
= pImpRec
->nShapeId
;
1077 auto nShapeOrder
= (static_cast<sal_uLong
>(pImpRec
->aTextId
.nTxBxS
) << 16)
1078 + pImpRec
->aTextId
.nSequence
;
1079 // Complement Import Record List
1080 pImpRec
->pObj
= pObj
;
1081 rImportData
.insert(std::move(pImpRec
));
1083 // Complement entry in Z Order List with a pointer to this Object
1084 // Only store objects which are not deep inside the tree
1085 if( ( rObjData
.nCalledByGroup
== 0 )
1087 ( (rObjData
.nSpFlags
& ShapeFlag::Group
)
1088 && (rObjData
.nCalledByGroup
< 2) )
1091 StoreShapeOrder(nShapeId
, nShapeOrder
, pObj
.get());
1098 sal_uInt32 nBufferSize
= GetPropertyValue( DFF_Prop_pihlShape
, 0 );
1099 if( (0 < nBufferSize
) && (nBufferSize
<= 0xFFFF) && SeekToContent( DFF_Prop_pihlShape
, rSt
) )
1101 SvMemoryStream aMemStream
;
1102 struct HyperLinksTable hlStr
;
1103 aMemStream
.WriteUInt16( 0 ).WriteUInt16( nBufferSize
);
1105 // copy from DFF stream to memory stream
1106 std::vector
< sal_uInt8
> aBuffer( nBufferSize
);
1107 if (rSt
.ReadBytes(aBuffer
.data(), nBufferSize
) == nBufferSize
)
1109 aMemStream
.WriteBytes(aBuffer
.data(), nBufferSize
);
1110 sal_uInt64 nStreamSize
= aMemStream
.TellEnd();
1111 aMemStream
.Seek( STREAM_SEEK_TO_BEGIN
);
1112 bool bRet
= 4 <= nStreamSize
;
1113 sal_uInt16 nRawRecId
,nRawRecSize
;
1115 aMemStream
.ReadUInt16( nRawRecId
).ReadUInt16( nRawRecSize
);
1116 SwDocShell
* pDocShell
= m_rReader
.m_pDocShell
;
1119 m_rReader
.ReadEmbeddedData(aMemStream
, pDocShell
, hlStr
);
1123 if (pObj
&& !hlStr
.hLinkAddr
.isEmpty())
1125 SwMacroInfo
* pInfo
= GetMacroInfo( pObj
.get() );
1128 pInfo
->SetShapeId( rObjData
.nShapeId
);
1129 pInfo
->SetHlink( hlStr
.hLinkAddr
);
1130 if (!hlStr
.tarFrame
.isEmpty())
1131 pInfo
->SetTarFrame( hlStr
.tarFrame
);
1132 OUString aNameStr
= GetPropertyString( DFF_Prop_wzName
, rSt
);
1133 if (!aNameStr
.isEmpty())
1134 pInfo
->SetName( aNameStr
);
1143 * Special FastSave - Attributes
1145 void SwWW8ImplReader::Read_StyleCode( sal_uInt16
, const sal_uInt8
* pData
, short nLen
)
1149 m_bCpxStyle
= false;
1152 sal_uInt16 nColl
= 0;
1153 if (m_xWwFib
->GetFIBVersion() <= ww::eWW2
)
1156 nColl
= SVBT16ToUInt16(pData
);
1157 if (nColl
< m_vColl
.size())
1159 SetTextFormatCollAndListLevel( *m_pPaM
, m_vColl
[nColl
] );
1165 * Read_Majority is for Majority (103) and Majority50 (108)
1167 void SwWW8ImplReader::Read_Majority( sal_uInt16
, const sal_uInt8
* , short )
1174 void SwWW8FltControlStack::NewAttr(const SwPosition
& rPos
,
1175 const SfxPoolItem
& rAttr
)
1177 OSL_ENSURE(RES_TXTATR_FIELD
!= rAttr
.Which(), "probably don't want to put"
1178 "fields into the control stack");
1179 OSL_ENSURE(RES_TXTATR_INPUTFIELD
!= rAttr
.Which(), "probably don't want to put"
1180 "input fields into the control stack");
1181 OSL_ENSURE(RES_TXTATR_ANNOTATION
!= rAttr
.Which(), "probably don't want to put"
1182 "annotations into the control stack");
1183 OSL_ENSURE(RES_FLTR_REDLINE
!= rAttr
.Which(), "probably don't want to put"
1184 "redlines into the control stack");
1185 SwFltControlStack::NewAttr(rPos
, rAttr
);
1188 SwFltStackEntry
* SwWW8FltControlStack::SetAttr(const SwPosition
& rPos
, sal_uInt16 nAttrId
,
1189 bool bTstEnd
, tools::Long nHand
, bool )
1191 SwFltStackEntry
*pRet
= nullptr;
1192 // Doing a textbox, and using the control stack only as a temporary
1193 // collection point for properties which will are not to be set into
1194 // the real document
1195 if (m_rReader
.m_xPlcxMan
&& m_rReader
.m_xPlcxMan
->GetDoingDrawTextBox())
1197 size_t nCnt
= size();
1198 for (size_t i
=0; i
< nCnt
; ++i
)
1200 SwFltStackEntry
& rEntry
= (*this)[i
];
1201 if (nAttrId
== rEntry
.m_pAttr
->Which())
1203 DeleteAndDestroy(i
--);
1208 else // Normal case, set the attribute into the document
1209 pRet
= SwFltControlStack::SetAttr(rPos
, nAttrId
, bTstEnd
, nHand
);
1213 tools::Long
GetListFirstLineIndent(const SwNumFormat
&rFormat
)
1215 OSL_ENSURE( rFormat
.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION
,
1216 "<GetListFirstLineIndent> - misusage: position-and-space-mode does not equal LABEL_WIDTH_AND_POSITION" );
1218 SvxAdjust eAdj
= rFormat
.GetNumAdjust();
1219 tools::Long nReverseListIndented
;
1220 if (eAdj
== SvxAdjust::Right
)
1221 nReverseListIndented
= -rFormat
.GetCharTextDistance();
1222 else if (eAdj
== SvxAdjust::Center
)
1223 nReverseListIndented
= rFormat
.GetFirstLineOffset()/2;
1225 nReverseListIndented
= rFormat
.GetFirstLineOffset();
1226 return nReverseListIndented
;
1229 static tools::Long
lcl_GetTrueMargin(SvxFirstLineIndentItem
const& rFirstLine
,
1230 SvxTextLeftMarginItem
const& rLeftMargin
, const SwNumFormat
&rFormat
,
1231 tools::Long
&rFirstLinePos
)
1233 OSL_ENSURE( rFormat
.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION
,
1234 "<lcl_GetTrueMargin> - misusage: position-and-space-mode does not equal LABEL_WIDTH_AND_POSITION" );
1236 const tools::Long nBodyIndent
= rLeftMargin
.GetTextLeft();
1237 const tools::Long nFirstLineDiff
= rFirstLine
.GetTextFirstLineOffset();
1238 rFirstLinePos
= nBodyIndent
+ nFirstLineDiff
;
1240 const auto nPseudoListBodyIndent
= rFormat
.GetAbsLSpace();
1241 const tools::Long nReverseListIndented
= GetListFirstLineIndent(rFormat
);
1242 tools::Long nExtraListIndent
= nPseudoListBodyIndent
+ nReverseListIndented
;
1244 return std::max
<tools::Long
>(nExtraListIndent
, 0);
1249 void SyncIndentWithList( SvxFirstLineIndentItem
& rFirstLine
,
1250 SvxTextLeftMarginItem
& rLeftMargin
,
1251 const SwNumFormat
&rFormat
,
1252 const bool bFirstLineOfstSet
,
1253 const bool bLeftIndentSet
)
1255 if ( rFormat
.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION
)
1257 tools::Long nWantedFirstLinePos
;
1258 tools::Long nExtraListIndent
= lcl_GetTrueMargin(rFirstLine
, rLeftMargin
, rFormat
, nWantedFirstLinePos
);
1259 rLeftMargin
.SetTextLeft(nWantedFirstLinePos
- nExtraListIndent
);
1260 rFirstLine
.SetTextFirstLineOffset(0);
1262 else if ( rFormat
.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT
)
1264 if ( !bFirstLineOfstSet
&& bLeftIndentSet
&&
1265 rFormat
.GetFirstLineIndent() != 0 )
1267 rFirstLine
.SetTextFirstLineOffset(rFormat
.GetFirstLineIndent());
1269 else if ( bFirstLineOfstSet
&& !bLeftIndentSet
&&
1270 rFormat
.GetIndentAt() != 0 )
1272 rLeftMargin
.SetTextLeft(rFormat
.GetIndentAt());
1274 else if (!bFirstLineOfstSet
&& !bLeftIndentSet
)
1276 if ( rFormat
.GetFirstLineIndent() != 0 )
1278 rFirstLine
.SetTextFirstLineOffset(rFormat
.GetFirstLineIndent());
1280 if ( rFormat
.GetIndentAt() != 0 )
1282 rLeftMargin
.SetTextLeft(rFormat
.GetIndentAt());
1288 const SwNumFormat
* SwWW8FltControlStack::GetNumFormatFromStack(const SwPosition
&rPos
,
1289 const SwTextNode
&rTextNode
)
1291 const SwNumFormat
*pRet
= nullptr;
1292 const SfxPoolItem
*pItem
= GetStackAttr(rPos
, RES_FLTR_NUMRULE
);
1293 if (pItem
&& rTextNode
.GetNumRule())
1295 if (rTextNode
.IsCountedInList())
1297 OUString
sName(static_cast<const SfxStringItem
*>(pItem
)->GetValue());
1298 const SwNumRule
*pRule
= m_rDoc
.FindNumRulePtr(sName
);
1300 pRet
= GetNumFormatFromSwNumRuleLevel(*pRule
, rTextNode
.GetActualListLevel());
1306 void SwWW8ReferencedFltEndStack::SetAttrInDoc( const SwPosition
& rTmpPos
,
1307 SwFltStackEntry
& rEntry
)
1309 switch( rEntry
.m_pAttr
->Which() )
1311 case RES_FLTR_BOOKMARK
:
1313 // suppress insertion of bookmark, which is recognized as an internal bookmark used for table-of-content
1314 // and which is not referenced.
1315 bool bInsertBookmarkIntoDoc
= true;
1317 SwFltBookmark
* pFltBookmark
= dynamic_cast<SwFltBookmark
*>(rEntry
.m_pAttr
.get());
1318 if ( pFltBookmark
!= nullptr && pFltBookmark
->IsTOCBookmark() )
1320 const OUString
& rName
= pFltBookmark
->GetName();
1321 std::set
< OUString
, SwWW8::ltstr
>::const_iterator aResult
= m_aReferencedTOCBookmarks
.find(rName
);
1322 if ( aResult
== m_aReferencedTOCBookmarks
.end() )
1324 bInsertBookmarkIntoDoc
= false;
1327 if ( bInsertBookmarkIntoDoc
)
1329 SwFltEndStack::SetAttrInDoc( rTmpPos
, rEntry
);
1334 SwFltEndStack::SetAttrInDoc( rTmpPos
, rEntry
);
1340 void SwWW8FltControlStack::SetAttrInDoc(const SwPosition
& rTmpPos
,
1341 SwFltStackEntry
& rEntry
)
1343 switch (rEntry
.m_pAttr
->Which())
1348 case RES_MARGIN_FIRSTLINE
:
1349 case RES_MARGIN_TEXTLEFT
:
1352 Loop over the affected nodes and
1353 a) convert the word style absolute indent to indent relative
1354 to any numbering indent active on the nodes
1355 b) adjust the writer style tabstops relative to the old
1356 paragraph indent to be relative to the new paragraph indent
1358 SwPaM
aRegion(rTmpPos
);
1359 if (rEntry
.MakeRegion(m_rDoc
, aRegion
, SwFltStackEntry::RegionMode::NoCheck
))
1361 SvxFirstLineIndentItem
firstLineNew(RES_MARGIN_FIRSTLINE
);
1362 SvxTextLeftMarginItem
leftMarginNew(RES_MARGIN_TEXTLEFT
);
1363 if (rEntry
.m_pAttr
->Which() == RES_MARGIN_FIRSTLINE
)
1365 SvxFirstLineIndentItem
const firstLineEntry(*static_cast<SvxFirstLineIndentItem
*>(rEntry
.m_pAttr
.get()));
1366 firstLineNew
.SetTextFirstLineOffset(firstLineEntry
.GetTextFirstLineOffset(), firstLineEntry
.GetPropTextFirstLineOffset());
1367 firstLineNew
.SetAutoFirst(firstLineEntry
.IsAutoFirst());
1371 SvxTextLeftMarginItem
const leftMarginEntry(*static_cast<SvxTextLeftMarginItem
*>(rEntry
.m_pAttr
.get()));
1372 leftMarginNew
.SetTextLeft(leftMarginEntry
.GetTextLeft(), leftMarginEntry
.GetPropLeft());
1374 SwNodeOffset nStart
= aRegion
.Start()->GetNodeIndex();
1375 SwNodeOffset nEnd
= aRegion
.End()->GetNodeIndex();
1376 for(; nStart
<= nEnd
; ++nStart
)
1378 SwNode
* pNode
= m_rDoc
.GetNodes()[ nStart
];
1379 if (!pNode
|| !pNode
->IsTextNode())
1382 SwContentNode
* pNd
= static_cast<SwContentNode
*>(pNode
);
1383 SvxFirstLineIndentItem
firstLineOld(pNd
->GetAttr(RES_MARGIN_FIRSTLINE
));
1384 SvxTextLeftMarginItem
leftMarginOld(pNd
->GetAttr(RES_MARGIN_TEXTLEFT
));
1385 if (rEntry
.m_pAttr
->Which() == RES_MARGIN_FIRSTLINE
)
1387 leftMarginNew
.SetTextLeft(leftMarginOld
.GetTextLeft(), leftMarginOld
.GetPropLeft());
1391 firstLineNew
.SetTextFirstLineOffset(firstLineOld
.GetTextFirstLineOffset(), firstLineOld
.GetPropTextFirstLineOffset());
1392 firstLineNew
.SetAutoFirst(firstLineOld
.IsAutoFirst());
1395 SwTextNode
*pTextNode
= static_cast<SwTextNode
*>(pNode
);
1397 const SwNumFormat
* pNum
1398 = GetNumFormatFromStack(*aRegion
.GetPoint(), *pTextNode
);
1401 pNum
= GetNumFormatFromTextNode(*pTextNode
);
1407 const bool bFirstLineIndentSet
=
1408 ( m_rReader
.m_aTextNodesHavingFirstLineOfstSet
.end() !=
1409 m_rReader
.m_aTextNodesHavingFirstLineOfstSet
.find( pNode
) );
1411 const bool bLeftIndentSet
=
1412 ( m_rReader
.m_aTextNodesHavingLeftIndentSet
.end() !=
1413 m_rReader
.m_aTextNodesHavingLeftIndentSet
.find( pNode
) );
1414 SyncIndentWithList(firstLineNew
, leftMarginNew
, *pNum
,
1415 bFirstLineIndentSet
,
1419 if (firstLineNew
!= firstLineOld
)
1421 pNd
->SetAttr(firstLineNew
);
1423 if (leftMarginNew
!= leftMarginOld
)
1425 pNd
->SetAttr(leftMarginNew
);
1432 case RES_TXTATR_FIELD
:
1433 OSL_ENSURE(false, "What is a field doing in the control stack,"
1434 "probably should have been in the endstack");
1437 case RES_TXTATR_ANNOTATION
:
1438 OSL_ENSURE(false, "What is an annotation doing in the control stack,"
1439 "probably should have been in the endstack");
1442 case RES_TXTATR_INPUTFIELD
:
1443 OSL_ENSURE(false, "What is an input field doing in the control stack,"
1444 "probably should have been in the endstack");
1447 case RES_TXTATR_INETFMT
:
1449 SwPaM
aRegion(rTmpPos
);
1450 if (rEntry
.MakeRegion(m_rDoc
, aRegion
, SwFltStackEntry::RegionMode::NoCheck
))
1452 SwFrameFormat
*pFrame
;
1453 // If we have just one single inline graphic then
1454 // don't insert a field for the single frame, set
1455 // the frames hyperlink field attribute directly.
1456 pFrame
= SwWW8ImplReader::ContainsSingleInlineGraphic(aRegion
);
1457 if (nullptr != pFrame
)
1459 const SwFormatINetFormat
*pAttr
= static_cast<const SwFormatINetFormat
*>(
1460 rEntry
.m_pAttr
.get());
1462 aURL
.SetURL(pAttr
->GetValue(), false);
1463 aURL
.SetTargetFrameName(pAttr
->GetTargetFrame());
1464 pFrame
->SetFormatAttr(aURL
);
1468 m_rDoc
.getIDocumentContentOperations().InsertPoolItem(aRegion
, *rEntry
.m_pAttr
);
1474 SwFltControlStack::SetAttrInDoc(rTmpPos
, rEntry
);
1479 const SfxPoolItem
* SwWW8FltControlStack::GetFormatAttr(const SwPosition
& rPos
,
1482 const SfxPoolItem
*pItem
= GetStackAttr(rPos
, nWhich
);
1485 SwContentNode
const*const pNd
= rPos
.GetNode().GetContentNode();
1487 pItem
= &m_rDoc
.GetAttrPool().GetDefaultItem(nWhich
);
1491 If we're hunting for the indent on a paragraph and need to use the
1492 parent style indent, then return the indent in msword format, and
1493 not writer format, because that's the style that the filter works
1496 if (nWhich
== RES_MARGIN_FIRSTLINE
1497 || nWhich
== RES_MARGIN_TEXTLEFT
1498 || nWhich
== RES_MARGIN_RIGHT
)
1500 SfxItemState eState
= SfxItemState::DEFAULT
;
1501 if (const SfxItemSet
*pSet
= pNd
->GetpSwAttrSet())
1502 eState
= pSet
->GetItemState(nWhich
, false);
1503 if (eState
!= SfxItemState::SET
&& m_rReader
.m_nCurrentColl
< m_rReader
.m_vColl
.size())
1507 case RES_MARGIN_FIRSTLINE
:
1508 pItem
= m_rReader
.m_vColl
[m_rReader
.m_nCurrentColl
].m_pWordFirstLine
.get();
1510 case RES_MARGIN_TEXTLEFT
:
1511 pItem
= m_rReader
.m_vColl
[m_rReader
.m_nCurrentColl
].m_pWordLeftMargin
.get();
1513 case RES_MARGIN_RIGHT
:
1514 pItem
= m_rReader
.m_vColl
[m_rReader
.m_nCurrentColl
].m_pWordRightMargin
.get();
1521 If we're hunting for a character property, try and exact position
1522 within the text node for lookup
1524 if (pNd
->IsTextNode())
1526 const sal_Int32 nPos
= rPos
.GetContentIndex();
1527 m_xScratchSet
.reset(new SfxItemSet(m_rDoc
.GetAttrPool(), nWhich
, nWhich
));
1528 if (pNd
->GetTextNode()->GetParaAttr(*m_xScratchSet
, nPos
, nPos
))
1529 pItem
= m_xScratchSet
->GetItem(nWhich
);
1533 pItem
= &pNd
->GetAttr(nWhich
);
1539 const SfxPoolItem
* SwWW8FltControlStack::GetStackAttr(const SwPosition
& rPos
,
1542 SwFltPosition
aFltPos(rPos
);
1544 size_t nSize
= size();
1547 const SwFltStackEntry
& rEntry
= (*this)[ --nSize
];
1548 if (rEntry
.m_pAttr
->Which() == nWhich
)
1550 if ( (rEntry
.m_bOpen
) ||
1552 (rEntry
.m_aMkPos
.m_nNode
<= aFltPos
.m_nNode
) &&
1553 (rEntry
.m_aPtPos
.m_nNode
>= aFltPos
.m_nNode
) &&
1554 (rEntry
.m_aMkPos
.m_nContent
<= aFltPos
.m_nContent
) &&
1555 (rEntry
.m_aPtPos
.m_nContent
> aFltPos
.m_nContent
)
1559 * e.g. half-open range [0-3) so asking for properties at 3
1560 * means props that end at 3 are not included
1563 return rEntry
.m_pAttr
.get();
1570 bool SwWW8FltRefStack::IsFootnoteEdnBkmField(
1571 const SwFormatField
& rFormatField
,
1574 const SwField
* pField
= rFormatField
.GetField();
1575 sal_uInt16 nSubType
;
1576 if(pField
&& (SwFieldIds::GetRef
== pField
->Which())
1577 && ((REF_FOOTNOTE
== (nSubType
= pField
->GetSubType())) || (REF_ENDNOTE
== nSubType
))
1578 && !static_cast<const SwGetRefField
*>(pField
)->GetSetRefName().isEmpty())
1580 const IDocumentMarkAccess
* const pMarkAccess
= m_rDoc
.getIDocumentMarkAccess();
1581 IDocumentMarkAccess::const_iterator_t ppBkmk
=
1582 pMarkAccess
->findMark( static_cast<const SwGetRefField
*>(pField
)->GetSetRefName() );
1583 if(ppBkmk
!= pMarkAccess
->getAllMarksEnd())
1585 // find Sequence No of corresponding Foot-/Endnote
1586 rBkmNo
= ppBkmk
- pMarkAccess
->getAllMarksBegin();
1593 void SwWW8FltRefStack::SetAttrInDoc(const SwPosition
& rTmpPos
,
1594 SwFltStackEntry
& rEntry
)
1596 switch (rEntry
.m_pAttr
->Which())
1599 Look up these in our lists of bookmarks that were changed to
1600 variables, and replace the ref field with a var field, otherwise
1601 do normal (?) strange stuff
1603 case RES_TXTATR_FIELD
:
1604 case RES_TXTATR_ANNOTATION
:
1605 case RES_TXTATR_INPUTFIELD
:
1607 SwPaM
aPaM(rEntry
.m_aMkPos
.m_nNode
.GetNode(), SwNodeOffset(1), rEntry
.m_aMkPos
.m_nContent
);
1609 SwFormatField
& rFormatField
= *static_cast<SwFormatField
*>(rEntry
.m_pAttr
.get());
1610 SwField
* pField
= rFormatField
.GetField();
1612 if (!RefToVar(pField
, rEntry
))
1615 if( IsFootnoteEdnBkmField(rFormatField
, nBkmNo
) )
1617 ::sw::mark::IMark
const * const pMark
= m_rDoc
.getIDocumentMarkAccess()->getAllMarksBegin()[nBkmNo
];
1619 const SwPosition
& rBkMrkPos
= pMark
->GetMarkPos();
1621 SwTextNode
* pText
= rBkMrkPos
.GetNode().GetTextNode();
1622 if( pText
&& rBkMrkPos
.GetContentIndex() )
1624 SwTextAttr
* const pFootnote
= pText
->GetTextAttrForCharAt(
1625 rBkMrkPos
.GetContentIndex()-1, RES_TXTATR_FTN
);
1628 sal_uInt16 nRefNo
= static_cast<SwTextFootnote
*>(pFootnote
)->GetSeqRefNo();
1630 static_cast<SwGetRefField
*>(pField
)->SetSeqNo( nRefNo
);
1632 if( pFootnote
->GetFootnote().IsEndNote() )
1633 static_cast<SwGetRefField
*>(pField
)->SetSubType(REF_ENDNOTE
);
1639 m_rDoc
.getIDocumentContentOperations().InsertPoolItem(aPaM
, *rEntry
.m_pAttr
);
1640 MoveAttrs(*aPaM
.GetPoint());
1644 SwFltEndStack::SetAttrInDoc(rTmpPos
, rEntry
);
1647 case RES_FLTR_BOOKMARK
:
1648 OSL_ENSURE(false, "EndStck used with non field, not what we want");
1649 SwFltEndStack::SetAttrInDoc(rTmpPos
, rEntry
);
1655 For styles we will do our tabstop arithmetic in word style and adjust them to
1656 writer style after all the styles have been finished and the dust settles as
1657 to what affects what.
1659 For explicit attributes we turn the adjusted writer tabstops back into 0 based
1660 word indexes and we'll turn them back into writer indexes when setting them
1661 into the document. If explicit left indent exist which affects them, then this
1662 is handled when the explicit left indent is set into the document
1664 void SwWW8ImplReader::Read_Tab(sal_uInt16
, const sal_uInt8
* pData
, short nLen
)
1668 m_xCtrlStck
->SetAttr(*m_pPaM
->GetPoint(), RES_PARATR_TABSTOP
);
1672 sal_uInt8 nDel
= (nLen
> 0) ? pData
[0] : 0;
1673 const sal_uInt8
* pDel
= pData
+ 1; // Del - Array
1675 sal_uInt8 nIns
= (nLen
> nDel
*2+1) ? pData
[nDel
*2+1] : 0;
1676 const sal_uInt8
* pIns
= pData
+ 2*nDel
+ 2; // Ins - Array
1678 short nRequiredLength
= 2 + 2*nDel
+ 2*nIns
+ 1*nIns
;
1679 if (nRequiredLength
> nLen
)
1681 // would require more data than available to describe!
1682 // discard invalid record
1687 WW8_TBD
const * pTyp
= reinterpret_cast<WW8_TBD
const *>(pData
+ 2*nDel
+ 2*nIns
+ 2); // Type Array
1689 std::shared_ptr
<SvxTabStopItem
> aAttr(std::make_shared
<SvxTabStopItem
>(0, 0, SvxTabAdjust::Default
, RES_PARATR_TABSTOP
));
1691 const SwFormat
* pSty
= nullptr;
1692 sal_uInt16 nTabBase
;
1693 if (m_pCurrentColl
&& m_nCurrentColl
< m_vColl
.size()) // StyleDef
1695 nTabBase
= m_vColl
[m_nCurrentColl
].m_nBase
;
1696 if (nTabBase
< m_vColl
.size()) // Based On
1697 pSty
= m_vColl
[nTabBase
].m_pFormat
;
1701 nTabBase
= m_nCurrentColl
;
1702 if (m_nCurrentColl
< m_vColl
.size())
1703 pSty
= m_vColl
[m_nCurrentColl
].m_pFormat
;
1704 //TODO: figure out else here
1707 bool bFound
= false;
1708 std::unordered_set
<size_t> aLoopWatch
;
1709 while (pSty
&& !bFound
)
1711 const SvxTabStopItem
* pTabs
;
1712 bFound
= pSty
->GetAttrSet().GetItemState(RES_PARATR_TABSTOP
, false,
1713 &pTabs
) == SfxItemState::SET
;
1716 aAttr
.reset(pTabs
->Clone());
1720 sal_uInt16 nOldTabBase
= nTabBase
;
1721 // If based on another
1722 if (nTabBase
< m_vColl
.size())
1723 nTabBase
= m_vColl
[nTabBase
].m_nBase
;
1726 nTabBase
< m_vColl
.size() &&
1727 nOldTabBase
!= nTabBase
&&
1728 nTabBase
!= ww::stiNil
1731 // #i61789: Stop searching when next style is the same as the
1732 // current one (prevent loop)
1733 aLoopWatch
.insert(reinterpret_cast<size_t>(pSty
));
1734 if (nTabBase
< m_vColl
.size())
1735 pSty
= m_vColl
[nTabBase
].m_pFormat
;
1736 //TODO figure out the else branch
1738 if (aLoopWatch
.find(reinterpret_cast<size_t>(pSty
)) !=
1743 pSty
= nullptr; // Give up on the search
1747 SvxTabStop aTabStop
;
1748 for (short i
=0; i
< nDel
; ++i
)
1750 sal_uInt16 nPos
= aAttr
->GetPos(SVBT16ToUInt16(pDel
+ i
*2));
1751 if( nPos
!= SVX_TAB_NOTFOUND
)
1752 aAttr
->Remove( nPos
);
1755 for (short i
=0; i
< nIns
; ++i
)
1757 short nPos
= SVBT16ToUInt16(pIns
+ i
*2);
1758 aTabStop
.GetTabPos() = nPos
;
1759 switch( pTyp
[i
].aBits1
& 0x7 ) // pTyp[i].jc
1762 aTabStop
.GetAdjustment() = SvxTabAdjust::Left
;
1765 aTabStop
.GetAdjustment() = SvxTabAdjust::Center
;
1768 aTabStop
.GetAdjustment() = SvxTabAdjust::Right
;
1771 aTabStop
.GetAdjustment() = SvxTabAdjust::Decimal
;
1774 continue; // Ignore Bar
1777 switch( pTyp
[i
].aBits1
>> 3 & 0x7 )
1780 aTabStop
.GetFill() = ' ';
1783 aTabStop
.GetFill() = '.';
1786 aTabStop
.GetFill() = '-';
1790 aTabStop
.GetFill() = '_';
1794 sal_uInt16 nPos2
= aAttr
->GetPos( nPos
);
1795 if (nPos2
!= SVX_TAB_NOTFOUND
)
1796 aAttr
->Remove(nPos2
); // Or else Insert() refuses
1797 aAttr
->Insert(aTabStop
);
1804 // Here we have a tab definition which inserts no extra tabs, or deletes
1805 // no existing tabs. An older version of writer is probably the creator
1806 // of the document :-( . So if we are importing a style we can just
1807 // ignore it. But if we are importing into text we cannot as during
1808 // text SwWW8ImplReader::Read_Tab is called at the begin and end of
1809 // the range the attrib affects, and ignoring it would upset the
1811 if (!m_pCurrentColl
) // not importing into a style
1813 SvxTabStopItem aOrig
= pSty
?
1814 pSty
->GetFormatAttr(RES_PARATR_TABSTOP
) :
1815 m_rDoc
.GetAttrPool().GetDefaultItem(RES_PARATR_TABSTOP
);
1824 void SwWW8ImplReader::ImportDop()
1826 // correct the LastPrinted date in DocumentProperties
1827 uno::Reference
<document::XDocumentPropertiesSupplier
> xDPS(
1828 m_pDocShell
->GetModel(), uno::UNO_QUERY_THROW
);
1829 uno::Reference
<document::XDocumentProperties
> xDocuProps(
1830 xDPS
->getDocumentProperties());
1831 OSL_ENSURE(xDocuProps
.is(), "DocumentProperties is null");
1832 if (xDocuProps
.is())
1834 DateTime
aLastPrinted(
1835 msfilter::util::DTTM2DateTime(m_xWDop
->dttmLastPrint
));
1836 ::util::DateTime uDT
= aLastPrinted
.GetUNODateTime();
1837 xDocuProps
->setPrintDate(uDT
);
1840 // COMPATIBILITY FLAGS START
1842 // #i78951# - remember the unknown compatibility options
1843 // so as to export them out
1844 m_rDoc
.getIDocumentSettingAccess().Setn32DummyCompatibilityOptions1(m_xWDop
->GetCompatibilityOptions());
1845 m_rDoc
.getIDocumentSettingAccess().Setn32DummyCompatibilityOptions2(m_xWDop
->GetCompatibilityOptions2());
1847 // The distance between two paragraphs is the sum of the bottom distance of
1848 // the first paragraph and the top distance of the second one
1849 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::PARA_SPACE_MAX
, m_xWDop
->fDontUseHTMLAutoSpacing
);
1850 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::PARA_SPACE_MAX_AT_PAGES
, true );
1851 // move tabs on alignment
1852 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::TAB_COMPAT
, true);
1853 // #i24363# tab stops relative to indent
1854 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::TABS_RELATIVE_TO_INDENT
, false);
1856 m_rDoc
.getIDocumentSettingAccess().set(
1857 DocumentSettingId::APPLY_PARAGRAPH_MARK_FORMAT_TO_NUMBERING
, true);
1858 m_rDoc
.getIDocumentSettingAccess().set(
1859 DocumentSettingId::MS_WORD_COMP_TRAILING_BLANKS
, true);
1861 m_rDoc
.getIDocumentSettingAccess().set(
1862 DocumentSettingId::HEADER_SPACING_BELOW_LAST_PARA
, true);
1863 m_rDoc
.getIDocumentSettingAccess().set(
1864 DocumentSettingId::FRAME_AUTOWIDTH_WITH_MORE_PARA
, true);
1865 m_rDoc
.getIDocumentSettingAccess().set(
1866 DocumentSettingId::FOOTNOTE_IN_COLUMN_TO_PAGEEND
, true);
1868 // Import Default Tabs
1869 tools::Long nDefTabSiz
= m_xWDop
->dxaTab
;
1870 if( nDefTabSiz
< 56 )
1873 // We want exactly one DefaultTab
1874 SvxTabStopItem
aNewTab( 1, sal_uInt16(nDefTabSiz
), SvxTabAdjust::Default
, RES_PARATR_TABSTOP
);
1875 const_cast<SvxTabStop
&>(aNewTab
[0]).GetAdjustment() = SvxTabAdjust::Default
;
1877 m_rDoc
.GetAttrPool().SetPoolDefaultItem( aNewTab
);
1879 // Import zoom factor
1880 if (m_xWDop
->wScaleSaved
)
1883 sal_Int16 nZoomType
;
1884 switch (m_xWDop
->zkSaved
) {
1885 case 1: nZoomType
= sal_Int16(SvxZoomType::WHOLEPAGE
); break;
1886 case 2: nZoomType
= sal_Int16(SvxZoomType::PAGEWIDTH
); break;
1887 case 3: nZoomType
= sal_Int16(SvxZoomType::OPTIMAL
); break;
1888 default: nZoomType
= sal_Int16(SvxZoomType::PERCENT
); break;
1890 uno::Sequence
<beans::PropertyValue
> aViewProps( comphelper::InitPropertySequence({
1891 { "ZoomFactor", uno::Any(sal_Int16(m_xWDop
->wScaleSaved
)) },
1892 { "VisibleBottom", uno::Any(sal_Int32(0)) },
1893 { "ZoomType", uno::Any(nZoomType
) }
1896 rtl::Reference
< comphelper::IndexedPropertyValuesContainer
> xBox
= new comphelper::IndexedPropertyValuesContainer();
1897 xBox
->insertByIndex(sal_Int32(0), uno::Any(aViewProps
));
1898 uno::Reference
<document::XViewDataSupplier
> xViewDataSupplier(m_pDocShell
->GetModel(), uno::UNO_QUERY
);
1899 xViewDataSupplier
->setViewData(xBox
);
1902 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::USE_VIRTUAL_DEVICE
, !m_xWDop
->fUsePrinterMetrics
);
1903 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::USE_HIRES_VIRTUAL_DEVICE
, true);
1904 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::ADD_FLY_OFFSETS
, true );
1906 // No vertical offsets would lead to e.g. overlap of table and fly frames.
1907 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::ADD_VERTICAL_FLY_OFFSETS
, true );
1909 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::ADD_EXT_LEADING
, !m_xWDop
->fNoLeading
);
1910 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::OLD_NUMBERING
, false);
1911 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING
, false); // #i47448#
1912 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::DO_NOT_JUSTIFY_LINES_WITH_MANUAL_BREAK
, !m_xWDop
->fExpShRtn
); // #i49277#, #i56856#
1913 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::DO_NOT_RESET_PARA_ATTRS_FOR_NUM_FONT
, false); // #i53199#
1914 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::OLD_LINE_SPACING
, false);
1916 // #i25901# - set new compatibility option
1917 // 'Add paragraph and table spacing at bottom of table cells'
1918 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::ADD_PARA_SPACING_TO_TABLE_CELLS
, true);
1919 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::ADD_PARA_LINE_SPACING_TO_TABLE_CELLS
, true);
1921 // #i11860# - set new compatibility option
1922 // 'Use former object positioning' to <false>
1923 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::USE_FORMER_OBJECT_POS
, false);
1925 // #i27767# - set new compatibility option
1926 // 'Consider Wrapping mode when positioning object' to <true>
1927 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION
, true);
1929 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::USE_FORMER_TEXT_WRAPPING
, false); // #i13832#, #i24135#
1931 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::TABLE_ROW_KEEP
, true); //SetTableRowKeep( true );
1933 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::IGNORE_TABS_AND_BLANKS_FOR_LINE_CALCULATION
, true); // #i3952#
1935 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::INVERT_BORDER_SPACING
, true);
1936 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::COLLAPSE_EMPTY_CELL_PARA
, true);
1937 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::UNBREAKABLE_NUMBERINGS
, true);
1938 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::CLIPPED_PICTURES
, true);
1939 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::TAB_OVER_MARGIN
, true);
1940 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::SURROUND_TEXT_WRAP_SMALL
, true);
1941 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::PROP_LINE_SPACING_SHRINKS_FIRST_LINE
, true);
1942 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::CONTINUOUS_ENDNOTES
, true);
1943 // rely on default for HYPHENATE_URLS=false
1945 IDocumentSettingAccess
& rIDSA
= m_rDoc
.getIDocumentSettingAccess();
1946 if (m_xWDop
->fDontBreakWrappedTables
)
1948 rIDSA
.set(DocumentSettingId::DO_NOT_BREAK_WRAPPED_TABLES
, true);
1951 // COMPATIBILITY FLAGS END
1953 // Import magic doptypography information, if it's there
1954 if (m_xWwFib
->m_nFib
> 105)
1955 ImportDopTypography(m_xWDop
->doptypography
);
1957 // disable form design mode to be able to use imported controls directly
1958 // #i31239# always disable form design mode, not only in protected docs
1959 uno::Reference
<beans::XPropertySet
> xDocProps(m_pDocShell
->GetModel(), uno::UNO_QUERY
);
1962 uno::Reference
<beans::XPropertySetInfo
> xInfo
= xDocProps
->getPropertySetInfo();
1965 if (xInfo
->hasPropertyByName("ApplyFormDesignMode"))
1966 xDocProps
->setPropertyValue("ApplyFormDesignMode", css::uno::Any(false));
1969 // for the benefit of DOCX - if this is ever saved in that format.
1970 comphelper::SequenceAsHashMap
aGrabBag(xDocProps
->getPropertyValue("InteropGrabBag"));
1971 uno::Sequence
<beans::PropertyValue
> aCompatSetting( comphelper::InitPropertySequence({
1972 { "name", uno::Any(OUString("compatibilityMode")) },
1973 { "uri", uno::Any(OUString("http://schemas.microsoft.com/office/word")) },
1974 { "val", uno::Any(OUString("11")) } //11: Use features specified in MS-DOC.
1977 uno::Sequence
< beans::PropertyValue
> aValue(comphelper::InitPropertySequence({
1978 { "compatSetting", uno::Any(aCompatSetting
) }
1981 aGrabBag
["CompatSettings"] <<= aValue
;
1982 xDocProps
->setPropertyValue("InteropGrabBag", uno::Any(aGrabBag
.getAsConstPropertyValueList()));
1985 // The password can force read-only, comments-only, fill-in-form-only, or require track-changes.
1986 // Treat comments-only like read-only since Writer has no support for that.
1987 // Still allow editing of form fields, without requiring the password.
1988 // Still allow editing if track-changes is locked on. (Currently LockRev is ignored/lost on export anyway.)
1989 if (!m_xWDop
->fProtEnabled
&& !m_xWDop
->fLockRev
)
1990 m_pDocShell
->SetModifyPasswordHash(m_xWDop
->lKeyProtDoc
);
1991 else if ( xDocProps
.is() )
1993 comphelper::SequenceAsHashMap
aGrabBag(xDocProps
->getPropertyValue("InteropGrabBag"));
1994 aGrabBag
["FormPasswordHash"] <<= m_xWDop
->lKeyProtDoc
;
1995 xDocProps
->setPropertyValue("InteropGrabBag", uno::Any(aGrabBag
.getAsConstPropertyValueList()));
1998 const SvtFilterOptions
& rOpt
= SvtFilterOptions::Get();
1999 if (rOpt
.IsUseEnhancedFields())
2000 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::PROTECT_FORM
, m_xWDop
->fProtEnabled
);
2002 if (m_xWDop
->iGutterPos
)
2004 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::GUTTER_AT_TOP
, true);
2008 void SwWW8ImplReader::ImportDopTypography(const WW8DopTypography
&rTypo
)
2010 switch (rTypo
.m_iLevelOfKinsoku
)
2014 i18n::ForbiddenCharacters
aForbidden(OUString(+rTypo
.m_rgxchFPunct
),
2015 OUString(+rTypo
.m_rgxchLPunct
));
2016 // unary + makes sure not to accidentally call the
2017 // OUString(ConstCharArrayDetector<...>::TypeUtf16) ctor that takes the full
2018 // m_rgxchFPunct, m_rgxchLPunct arrays with embedded NULs, instead of just the
2019 // prefix leading up to the first NUL
2020 m_rDoc
.getIDocumentSettingAccess().setForbiddenCharacters(rTypo
.GetConvertedLang(),
2022 // Obviously cannot set the standard level 1 for japanese, so
2023 // bail out now while we can.
2024 if (rTypo
.GetConvertedLang() == LANGUAGE_JAPANESE
)
2033 This MS hack means that level 2 of japanese is not in operation, so we put
2034 in what we know are the MS defaults, there is a complementary reverse
2035 hack in the writer. Its our default as well, but we can set it anyway
2036 as a flag for later.
2038 if (!rTypo
.m_reserved2
)
2040 i18n::ForbiddenCharacters
aForbidden(WW8DopTypography::JapanNotBeginLevel1
,
2041 WW8DopTypography::JapanNotEndLevel1
);
2042 m_rDoc
.getIDocumentSettingAccess().setForbiddenCharacters(LANGUAGE_JAPANESE
,aForbidden
);
2045 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::KERN_ASIAN_PUNCTUATION
, bool(rTypo
.m_fKerningPunct
));
2046 m_rDoc
.getIDocumentSettingAccess().setCharacterCompressionType(static_cast<CharCompressType
>(rTypo
.m_iJustification
));
2050 * Footnotes and Endnotes
2052 WW8ReaderSave::WW8ReaderSave(SwWW8ImplReader
* pRdr
,WW8_CP nStartCp
) :
2053 mxTmpPos(pRdr
->m_rDoc
.CreateUnoCursor(*pRdr
->m_pPaM
->GetPoint())),
2054 mxOldStck(std::move(pRdr
->m_xCtrlStck
)),
2055 mxOldAnchorStck(std::move(pRdr
->m_xAnchorStck
)),
2056 mxOldRedlines(std::move(pRdr
->m_xRedlineStack
)),
2057 mxOldPlcxMan(pRdr
->m_xPlcxMan
),
2058 mpWFlyPara(std::move(pRdr
->m_xWFlyPara
)),
2059 mpSFlyPara(std::move(pRdr
->m_xSFlyPara
)),
2060 mpPreviousNumPaM(pRdr
->m_pPreviousNumPaM
),
2061 mpPrevNumRule(pRdr
->m_pPrevNumRule
),
2062 mxTableDesc(std::move(pRdr
->m_xTableDesc
)),
2063 mnInTable(pRdr
->m_nInTable
),
2064 mnCurrentColl(pRdr
->m_nCurrentColl
),
2065 mcSymbol(pRdr
->m_cSymbol
),
2066 mbIgnoreText(pRdr
->m_bIgnoreText
),
2067 mbSymbol(pRdr
->m_bSymbol
),
2068 mbHdFtFootnoteEdn(pRdr
->m_bHdFtFootnoteEdn
),
2069 mbTxbxFlySection(pRdr
->m_bTxbxFlySection
),
2070 mbAnl(pRdr
->m_bAnl
),
2071 mbInHyperlink(pRdr
->m_bInHyperlink
),
2072 mbPgSecBreak(pRdr
->m_bPgSecBreak
),
2073 mbWasParaEnd(pRdr
->m_bWasParaEnd
),
2074 mbHasBorder(pRdr
->m_bHasBorder
),
2075 mbFirstPara(pRdr
->m_bFirstPara
)
2077 pRdr
->m_bSymbol
= false;
2078 pRdr
->m_bHdFtFootnoteEdn
= true;
2079 pRdr
->m_bTxbxFlySection
= pRdr
->m_bAnl
= pRdr
->m_bPgSecBreak
= pRdr
->m_bWasParaEnd
2080 = pRdr
->m_bHasBorder
= false;
2081 pRdr
->m_bFirstPara
= true;
2082 pRdr
->m_nInTable
= 0;
2083 pRdr
->m_pPreviousNumPaM
= nullptr;
2084 pRdr
->m_pPrevNumRule
= nullptr;
2085 pRdr
->m_nCurrentColl
= 0;
2087 pRdr
->m_xCtrlStck
.reset(new SwWW8FltControlStack(pRdr
->m_rDoc
, pRdr
->m_nFieldFlags
,
2090 pRdr
->m_xRedlineStack
.reset(new sw::util::RedlineStack(pRdr
->m_rDoc
));
2092 pRdr
->m_xAnchorStck
.reset(new SwWW8FltAnchorStack(pRdr
->m_rDoc
, pRdr
->m_nFieldFlags
));
2094 // Save the attribute manager: we need this as the newly created PLCFx Manager
2095 // access the same FKPs as the old one and their Start-End position changes.
2096 if (pRdr
->m_xPlcxMan
)
2097 pRdr
->m_xPlcxMan
->SaveAllPLCFx(maPLCFxSave
);
2101 pRdr
->m_xPlcxMan
= std::make_shared
<WW8PLCFMan
>(pRdr
->m_xSBase
.get(),
2102 mxOldPlcxMan
->GetManType(), nStartCp
);
2105 maOldApos
.push_back(false);
2106 maOldApos
.swap(pRdr
->m_aApos
);
2107 maOldFieldStack
.swap(pRdr
->m_aFieldStack
);
2110 void WW8ReaderSave::Restore( SwWW8ImplReader
* pRdr
)
2112 pRdr
->m_xWFlyPara
= std::move(mpWFlyPara
);
2113 pRdr
->m_xSFlyPara
= std::move(mpSFlyPara
);
2114 pRdr
->m_pPreviousNumPaM
= mpPreviousNumPaM
;
2115 pRdr
->m_pPrevNumRule
= mpPrevNumRule
;
2116 pRdr
->m_xTableDesc
= std::move(mxTableDesc
);
2117 pRdr
->m_cSymbol
= mcSymbol
;
2118 pRdr
->m_bSymbol
= mbSymbol
;
2119 pRdr
->m_bIgnoreText
= mbIgnoreText
;
2120 pRdr
->m_bHdFtFootnoteEdn
= mbHdFtFootnoteEdn
;
2121 pRdr
->m_bTxbxFlySection
= mbTxbxFlySection
;
2122 pRdr
->m_nInTable
= mnInTable
;
2123 pRdr
->m_bAnl
= mbAnl
;
2124 pRdr
->m_bInHyperlink
= mbInHyperlink
;
2125 pRdr
->m_bWasParaEnd
= mbWasParaEnd
;
2126 pRdr
->m_bPgSecBreak
= mbPgSecBreak
;
2127 pRdr
->m_nCurrentColl
= mnCurrentColl
;
2128 pRdr
->m_bHasBorder
= mbHasBorder
;
2129 pRdr
->m_bFirstPara
= mbFirstPara
;
2131 // Close all attributes as attributes could be created that extend the Fly
2132 pRdr
->DeleteCtrlStack();
2133 pRdr
->m_xCtrlStck
= std::move(mxOldStck
);
2135 pRdr
->m_xRedlineStack
->closeall(*pRdr
->m_pPaM
->GetPoint());
2137 // ofz#37322 drop m_oLastAnchorPos during RedlineStack dtor and restore it afterwards to the same
2138 // place, or somewhere close if that place got destroyed
2139 std::shared_ptr
<SwUnoCursor
> xLastAnchorCursor(pRdr
->m_oLastAnchorPos
? pRdr
->m_rDoc
.CreateUnoCursor(*pRdr
->m_oLastAnchorPos
) : nullptr);
2140 pRdr
->m_oLastAnchorPos
.reset();
2142 pRdr
->m_xRedlineStack
= std::move(mxOldRedlines
);
2144 if (xLastAnchorCursor
)
2145 pRdr
->m_oLastAnchorPos
.emplace(*xLastAnchorCursor
->GetPoint());
2147 pRdr
->DeleteAnchorStack();
2148 pRdr
->m_xAnchorStck
= std::move(mxOldAnchorStck
);
2150 *pRdr
->m_pPaM
->GetPoint() = GetStartPos();
2152 if (mxOldPlcxMan
!= pRdr
->m_xPlcxMan
)
2153 pRdr
->m_xPlcxMan
= mxOldPlcxMan
;
2154 if (pRdr
->m_xPlcxMan
)
2155 pRdr
->m_xPlcxMan
->RestoreAllPLCFx(maPLCFxSave
);
2156 pRdr
->m_aApos
.swap(maOldApos
);
2157 pRdr
->m_aFieldStack
.swap(maOldFieldStack
);
2160 void SwWW8ImplReader::Read_HdFtFootnoteText( const SwNodeIndex
* pSttIdx
,
2161 WW8_CP nStartCp
, WW8_CP nLen
, ManTypes nType
)
2163 if (nStartCp
< 0 || nLen
< 0)
2166 // Saves Flags (amongst other things) and resets them
2167 WW8ReaderSave
aSave( this );
2169 m_pPaM
->GetPoint()->Assign( pSttIdx
->GetIndex() + 1 );
2171 // Read Text for Header, Footer or Footnote
2172 ReadText( nStartCp
, nLen
, nType
); // Ignore Sepx when doing so
2173 aSave
.Restore( this );
2177 * Use authornames, if not available fall back to initials.
2179 tools::Long
SwWW8ImplReader::Read_And(WW8PLCFManResult
* pRes
)
2181 WW8PLCFx_SubDoc
* pSD
= m_xPlcxMan
->GetAtn();
2185 const void* pData
= pSD
->GetData();
2193 const WW67_ATRD
* pDescri
= static_cast<const WW67_ATRD
*>(pData
);
2194 const OUString
* pA
= GetAnnotationAuthor(SVBT16ToUInt16(pDescri
->ibst
));
2199 const sal_uInt8 nLen
= std::min
<sal_uInt8
>(pDescri
->xstUsrInitl
[0],
2200 SAL_N_ELEMENTS(pDescri
->xstUsrInitl
)-1);
2201 sAuthor
= OUString(pDescri
->xstUsrInitl
+ 1, nLen
, RTL_TEXTENCODING_MS_1252
);
2206 const WW8_ATRD
* pDescri
= static_cast<const WW8_ATRD
*>(pData
);
2208 const sal_uInt16 nLen
= std::min
<sal_uInt16
>(SVBT16ToUInt16(pDescri
->xstUsrInitl
[0]),
2209 SAL_N_ELEMENTS(pDescri
->xstUsrInitl
)-1);
2210 OUStringBuffer aBuf
;
2211 aBuf
.setLength(nLen
);
2212 for(sal_uInt16 nIdx
= 1; nIdx
<= nLen
; ++nIdx
)
2213 aBuf
[nIdx
-1] = SVBT16ToUInt16(pDescri
->xstUsrInitl
[nIdx
]);
2214 sInitials
= aBuf
.makeStringAndClear();
2217 if (const OUString
* pA
= GetAnnotationAuthor(SVBT16ToUInt16(pDescri
->ibst
)))
2220 sAuthor
= sInitials
;
2223 sal_uInt32 nDateTime
= 0;
2225 if (sal_uInt8
* pExtended
= m_xPlcxMan
->GetExtendedAtrds()) // Word < 2002 has no date data for comments
2227 sal_uLong nIndex
= pSD
->GetIdx() & 0xFFFF; // Index is (stupidly) multiplexed for WW8PLCFx_SubDocs
2228 if (m_xWwFib
->m_lcbAtrdExtra
/18 > nIndex
)
2229 nDateTime
= SVBT32ToUInt32(*reinterpret_cast<SVBT32
*>(pExtended
+(nIndex
*18)));
2232 DateTime aDate
= msfilter::util::DTTM2DateTime(nDateTime
);
2235 std::optional
<OutlinerParaObject
> pOutliner
= ImportAsOutliner( sText
, pRes
->nCp2OrIdx
,
2236 pRes
->nCp2OrIdx
+ pRes
->nMemLen
, MAN_AND
);
2238 m_xFormatOfJustInsertedApo
.reset();
2239 SwPostItField
aPostIt(
2240 static_cast<SwPostItFieldType
*>(m_rDoc
.getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::Postit
)), sAuthor
,
2241 sText
, sInitials
, OUString(), aDate
);
2242 aPostIt
.SetTextObject(std::move(pOutliner
));
2244 SwPaM
aEnd(*m_pPaM
->End(), *m_pPaM
->End());
2245 m_xCtrlStck
->NewAttr(*aEnd
.GetPoint(), SvxCharHiddenItem(false, RES_CHRATR_HIDDEN
));
2246 m_rDoc
.getIDocumentContentOperations().InsertPoolItem(aEnd
, SwFormatField(aPostIt
));
2247 m_xCtrlStck
->SetAttr(*aEnd
.GetPoint(), RES_CHRATR_HIDDEN
);
2248 // If this is a range, make sure that it ends after the just inserted character, not before it.
2249 m_xReffedStck
->MoveAttrs(*aEnd
.GetPoint(), SwFltControlStack::MoveAttrsMode::POSTIT_INSERTED
);
2254 void SwWW8ImplReader::Read_HdFtTextAsHackedFrame(WW8_CP nStart
, WW8_CP nLen
,
2255 SwFrameFormat
const &rHdFtFormat
, sal_uInt16 nPageWidth
)
2257 const SwNodeIndex
* pSttIdx
= rHdFtFormat
.GetContent().GetContentIdx();
2258 OSL_ENSURE(pSttIdx
, "impossible");
2262 SwPosition
aTmpPos(*m_pPaM
->GetPoint());
2264 m_pPaM
->GetPoint()->Assign( pSttIdx
->GetIndex() + 1 );
2266 // tdf#122425: Explicitly remove borders and spacing
2267 SfxItemSetFixed
<RES_FRMATR_BEGIN
, RES_FRMATR_END
- 1> aFlySet(m_rDoc
.GetAttrPool());
2268 Reader::ResetFrameFormatAttrs(aFlySet
);
2270 SwFlyFrameFormat
* pFrame
2271 = m_rDoc
.MakeFlySection(RndStdIds::FLY_AT_PARA
, m_pPaM
->GetPoint(), &aFlySet
);
2273 SwFormatAnchor
aAnch( pFrame
->GetAnchor() );
2274 aAnch
.SetType( RndStdIds::FLY_AT_PARA
);
2275 pFrame
->SetFormatAttr( aAnch
);
2276 SwFormatFrameSize
aSz(SwFrameSize::Minimum
, nPageWidth
, MINLAY
);
2277 SwFrameSize eFrameSize
= SwFrameSize::Minimum
;
2278 if( eFrameSize
!= aSz
.GetWidthSizeType() )
2279 aSz
.SetWidthSizeType( eFrameSize
);
2280 pFrame
->SetFormatAttr(aSz
);
2281 pFrame
->SetFormatAttr(SwFormatSurround(css::text::WrapTextMode_THROUGH
));
2282 pFrame
->SetFormatAttr(SwFormatHoriOrient(0, text::HoriOrientation::LEFT
)); //iFOO
2284 // #i43427# - send frame for header/footer into background.
2285 pFrame
->SetFormatAttr( SvxOpaqueItem( RES_OPAQUE
, false ) );
2286 SdrObject
* pFrameObj
= CreateContactObject( pFrame
);
2287 OSL_ENSURE( pFrameObj
,
2288 "<SwWW8ImplReader::Read_HdFtTextAsHackedFrame(..)> - missing SdrObject instance" );
2291 pFrameObj
->SetOrdNum( 0 );
2293 MoveInsideFly(pFrame
);
2295 const SwNodeIndex
* pHackIdx
= pFrame
->GetContent().GetContentIdx();
2297 Read_HdFtFootnoteText(pHackIdx
, nStart
, nLen
- 1, MAN_HDFT
);
2299 MoveOutsideFly(pFrame
, aTmpPos
);
2302 void SwWW8ImplReader::Read_HdFtText(WW8_CP nStart
, WW8_CP nLen
, SwFrameFormat
const * pHdFtFormat
)
2304 const SwNodeIndex
* pSttIdx
= pHdFtFormat
->GetContent().GetContentIdx();
2308 SwPosition
aTmpPos( *m_pPaM
->GetPoint() ); // Remember old cursor position
2310 Read_HdFtFootnoteText(pSttIdx
, nStart
, nLen
- 1, MAN_HDFT
);
2312 *m_pPaM
->GetPoint() = aTmpPos
;
2315 bool SwWW8ImplReader::isValid_HdFt_CP(WW8_CP nHeaderCP
) const
2317 // Each CP of Plcfhdd MUST be less than FibRgLw97.ccpHdd
2318 return (nHeaderCP
< m_xWwFib
->m_ccpHdr
&& nHeaderCP
>= 0);
2321 bool SwWW8ImplReader::HasOwnHeaderFooter(sal_uInt8 nWhichItems
, sal_uInt8 grpfIhdt
,
2326 WW8_CP nStart
, nLen
;
2327 sal_uInt8 nNumber
= 5;
2329 for( sal_uInt8 nI
= 0x20; nI
; nI
>>= 1, nNumber
-- )
2331 if (nI
& nWhichItems
)
2335 bOk
= ( m_xHdFt
->GetTextPos(grpfIhdt
, nI
, nStart
, nLen
) && nStart
>= 0 && nLen
>= 2 );
2338 m_xHdFt
->GetTextPosExact( static_cast< short >(nNumber
+ (nSect
+1)*6), nStart
, nLen
);
2339 bOk
= ( 2 <= nLen
) && isValid_HdFt_CP(nStart
);
2350 void SwWW8ImplReader::Read_HdFt(int nSect
, const SwPageDesc
*pPrev
,
2351 const wwSection
&rSection
)
2353 sal_uInt8 grpfIhdt
= rSection
.maSep
.grpfIhdt
;
2354 SwPageDesc
*pPD
= rSection
.mpPage
;
2359 WW8_CP nStart
, nLen
;
2360 sal_uInt8 nNumber
= 5;
2362 // This loops through the 6 flags WW8_{FOOTER,HEADER}_{ODD,EVEN,FIRST}
2363 // corresponding to bit fields in grpfIhdt indicating which
2364 // header/footer(s) are present in this section
2365 for( sal_uInt8 nI
= 0x20; nI
; nI
>>= 1, nNumber
-- )
2371 bOk
= ( m_xHdFt
->GetTextPos(grpfIhdt
, nI
, nStart
, nLen
) && nLen
>= 2 );
2374 m_xHdFt
->GetTextPosExact( static_cast< short >(nNumber
+ (nSect
+1)*6), nStart
, nLen
);
2375 bOk
= ( 2 <= nLen
) && isValid_HdFt_CP(nStart
);
2379 = (nI
& ( WW8_HEADER_EVEN
| WW8_FOOTER_EVEN
)) != 0;
2381 = (nI
& ( WW8_HEADER_FIRST
| WW8_FOOTER_FIRST
)) != 0;
2383 // If we are loading a first-page header/footer which is not
2384 // actually enabled in this section (it still needs to be
2385 // loaded as it may be inherited by a later section)
2386 bool bDisabledFirst
= bUseFirst
&& !rSection
.HasTitlePage();
2389 = (nI
& ( WW8_FOOTER_EVEN
| WW8_FOOTER_ODD
| WW8_FOOTER_FIRST
)) != 0;
2391 SwFrameFormat
& rFormat
= bUseLeft
? pPD
->GetLeft()
2392 : bUseFirst
? pPD
->GetFirstMaster()
2395 SwFrameFormat
* pHdFtFormat
;
2396 // If we have empty first page header and footer.
2397 bool bNoFirst
= !(grpfIhdt
& WW8_HEADER_FIRST
) && !(grpfIhdt
& WW8_FOOTER_FIRST
);
2401 //#i17196# Cannot have left without right
2403 && !pPD
->GetMaster().GetFooter().GetFooterFormat())
2404 pPD
->GetMaster().SetFormatAttr(SwFormatFooter(true));
2406 pPD
->GetLeft().SetFormatAttr(SwFormatFooter(true));
2407 if (bUseFirst
|| (rSection
.maSep
.fTitlePage
&& bNoFirst
))
2408 pPD
->GetFirstMaster().SetFormatAttr(SwFormatFooter(true));
2409 pHdFtFormat
= const_cast<SwFrameFormat
*>(rFormat
.GetFooter().GetFooterFormat());
2414 //#i17196# Cannot have left without right
2416 && !pPD
->GetMaster().GetHeader().GetHeaderFormat())
2417 pPD
->GetMaster().SetFormatAttr(SwFormatHeader(true));
2419 pPD
->GetLeft().SetFormatAttr(SwFormatHeader(true));
2420 if (bUseFirst
|| (rSection
.maSep
.fTitlePage
&& bNoFirst
))
2421 pPD
->GetFirstMaster().SetFormatAttr(SwFormatHeader(true));
2422 pHdFtFormat
= const_cast<SwFrameFormat
*>(rFormat
.GetHeader().GetHeaderFormat());
2427 bool bHackRequired
= false;
2428 if (m_bIsHeader
&& rSection
.IsFixedHeightHeader())
2429 bHackRequired
= true;
2430 else if (m_bIsFooter
&& rSection
.IsFixedHeightFooter())
2431 bHackRequired
= true;
2435 Read_HdFtTextAsHackedFrame(nStart
, nLen
, *pHdFtFormat
,
2436 static_cast< sal_uInt16
>(rSection
.GetTextAreaWidth()) );
2439 Read_HdFtText(nStart
, nLen
, pHdFtFormat
);
2442 CopyPageDescHdFt(pPrev
, pPD
, nI
);
2444 m_bIsHeader
= m_bIsFooter
= false;
2449 bool wwSectionManager::SectionIsProtected(const wwSection
&rSection
) const
2451 return ( mrReader
.m_xWDop
->fProtEnabled
&& !rSection
.IsNotProtected() );
2454 void wwSectionManager::SetHdFt(wwSection
const &rSection
, int nSect
,
2455 const wwSection
*pPrevious
)
2457 // Header/Footer not present
2458 if (!rSection
.maSep
.grpfIhdt
)
2461 OSL_ENSURE(rSection
.mpPage
, "makes no sense to call with a main page");
2462 if (rSection
.mpPage
)
2464 mrReader
.Read_HdFt(nSect
, pPrevious
? pPrevious
->mpPage
: nullptr,
2468 // Header/Footer - Update Index
2469 // So that the index is still valid later on
2470 if (mrReader
.m_xHdFt
)
2471 mrReader
.m_xHdFt
->UpdateIndex(rSection
.maSep
.grpfIhdt
);
2475 void SwWW8ImplReader::AppendTextNode(SwPosition
& rPos
)
2477 SwTextNode
* pText
= m_pPaM
->GetPointNode().GetTextNode();
2479 const SwNumRule
* pRule
= nullptr;
2481 if (pText
!= nullptr)
2482 pRule
= sw::util::GetNumRuleFromTextNode(*pText
);
2484 // tdf#64222 / tdf#150613 filter out the "paragraph marker" formatting and
2485 // set it as a separate paragraph property, just like we do for DOCX.
2486 // This is only being used for numbering currently, so limiting to that context.
2489 SfxItemSetFixed
<RES_CHRATR_BEGIN
, RES_CHRATR_END
- 1, RES_TXTATR_CHARFMT
,
2490 RES_TXTATR_CHARFMT
, RES_UNKNOWNATR_BEGIN
, RES_UNKNOWNATR_END
- 1>
2491 items(m_pPaM
->GetDoc().GetAttrPool());
2493 SfxWhichIter
aIter(items
);
2494 for (sal_uInt16 nWhich
= aIter
.FirstWhich(); nWhich
; nWhich
= aIter
.NextWhich())
2496 const SfxPoolItem
* pItem
= m_xCtrlStck
->GetStackAttr(rPos
, nWhich
);
2500 SwFormatAutoFormat
item(RES_PARATR_LIST_AUTOFMT
);
2501 item
.SetStyleHandle(std::make_shared
<SfxItemSet
>(items
));
2502 pText
->SetAttr(item
);
2506 pRule
&& !m_xWDop
->fDontUseHTMLAutoSpacing
&&
2507 (m_bParaAutoBefore
|| m_bParaAutoAfter
)
2510 // If after spacing is set to auto, set the after space to 0
2511 if (m_bParaAutoAfter
)
2512 SetLowerSpacing(*m_pPaM
, 0);
2514 // If the previous textnode had numbering and
2515 // and before spacing is set to auto, set before space to 0
2516 if(m_pPrevNumRule
&& m_bParaAutoBefore
)
2517 SetUpperSpacing(*m_pPaM
, 0);
2519 // If the previous numbering rule was different we need
2520 // to insert a space after the previous paragraph
2521 if((pRule
!= m_pPrevNumRule
) && m_pPreviousNumPaM
)
2522 SetLowerSpacing(*m_pPreviousNumPaM
, GetParagraphAutoSpace(m_xWDop
->fDontUseHTMLAutoSpacing
));
2524 // cache current paragraph
2525 if(m_pPreviousNumPaM
)
2527 delete m_pPreviousNumPaM
;
2528 m_pPreviousNumPaM
= nullptr;
2531 m_pPreviousNumPaM
= new SwPaM(*m_pPaM
, m_pPaM
);
2532 m_pPrevNumRule
= pRule
;
2534 else if(!pRule
&& m_pPreviousNumPaM
)
2536 // If the previous paragraph has numbering but the current one does not
2537 // we need to add a space after the previous paragraph
2538 SetLowerSpacing(*m_pPreviousNumPaM
, GetParagraphAutoSpace(m_xWDop
->fDontUseHTMLAutoSpacing
));
2539 delete m_pPreviousNumPaM
;
2540 m_pPreviousNumPaM
= nullptr;
2541 m_pPrevNumRule
= nullptr;
2545 // clear paragraph cache
2546 if(m_pPreviousNumPaM
)
2548 delete m_pPreviousNumPaM
;
2549 m_pPreviousNumPaM
= nullptr;
2551 m_pPrevNumRule
= pRule
;
2554 // If this is the first paragraph in the document and
2555 // Auto-spacing before paragraph is set,
2556 // set the upper spacing value to 0
2557 if(m_bParaAutoBefore
&& m_bFirstPara
&& !m_xWDop
->fDontUseHTMLAutoSpacing
)
2558 SetUpperSpacing(*m_pPaM
, 0);
2560 m_bFirstPara
= false;
2562 m_rDoc
.getIDocumentContentOperations().AppendTextNode(rPos
);
2564 // We can flush all anchored graphics at the end of a paragraph.
2565 m_xAnchorStck
->Flush();
2568 bool SwWW8ImplReader::SetSpacing(SwPaM
&rMyPam
, int nSpace
, bool bIsUpper
)
2571 const SwPosition
* pSpacingPos
= rMyPam
.GetPoint();
2573 const SvxULSpaceItem
* pULSpaceItem
= m_xCtrlStck
->GetFormatAttr(*pSpacingPos
, RES_UL_SPACE
);
2575 if(pULSpaceItem
!= nullptr)
2577 SvxULSpaceItem
aUL(*pULSpaceItem
);
2580 aUL
.SetUpper( static_cast< sal_uInt16
>(nSpace
) );
2582 aUL
.SetLower( static_cast< sal_uInt16
>(nSpace
) );
2584 const sal_Int32 nEnd
= pSpacingPos
->GetContentIndex();
2585 rMyPam
.GetPoint()->SetContent(0);
2586 m_xCtrlStck
->NewAttr(*pSpacingPos
, aUL
);
2587 rMyPam
.GetPoint()->SetContent(nEnd
);
2588 m_xCtrlStck
->SetAttr(*pSpacingPos
, RES_UL_SPACE
);
2594 bool SwWW8ImplReader::SetLowerSpacing(SwPaM
&rMyPam
, int nSpace
)
2596 return SetSpacing(rMyPam
, nSpace
, false);
2599 bool SwWW8ImplReader::SetUpperSpacing(SwPaM
&rMyPam
, int nSpace
)
2601 return SetSpacing(rMyPam
, nSpace
, true);
2604 sal_uInt16
SwWW8ImplReader::TabRowSprm(int nLevel
) const
2607 return NS_sprm::v6::sprmPTtp
;
2608 return nLevel
? NS_sprm::PFInnerTtp::val
: NS_sprm::PFTtp::val
;
2611 void SwWW8ImplReader::EndSpecial()
2615 StopAllAnl(); // -> bAnl = false
2617 while(m_aApos
.size() > 1)
2622 if (m_aApos
[m_nInTable
])
2629 OSL_ENSURE(!m_nInTable
, "unclosed table!");
2632 bool SwWW8ImplReader::ProcessSpecial(bool &rbReSync
, WW8_CP nStartCp
)
2640 OSL_ENSURE(m_nInTable
>= 0,"nInTable < 0!");
2643 bool bTableRowEnd
= (m_xPlcxMan
->HasParaSprm(m_bVer67
? 25 : 0x2417).pSprm
!= nullptr);
2645 // Unfortunately, for every paragraph we need to check first whether
2646 // they contain a sprm 29 (0x261B), which starts an APO.
2647 // All other sprms then refer to that APO and not to the normal text
2649 // The same holds true for a Table (sprm 24 (0x2416)) and Anls (sprm 13).
2651 // WW: Table in APO is possible (Both Start-Ends occur at the same time)
2652 // WW: APO in Table not possible
2654 // This mean that of a Table is the content of an APO, the APO start needs
2655 // to be edited first, so that the Table remains in the APO and not the
2656 // other way around.
2657 // At the End, however, we need to edit the Table End first as the APO
2658 // must end after that Table (or else we never find the APO End).
2660 // The same holds true for Fly / Anl, Tab / Anl, Fly / Tab / Anl.
2662 // If the Table is within an APO the TabRowEnd Area misses the
2664 // To not end the APO there, we do not call ProcessApo
2666 // KHZ: When there is a table inside the Apo the Apo-flags are also
2667 // missing for the 2nd, 3rd... paragraphs of each cell.
2669 // 1st look for in-table flag, for 2000+ there is a subtable flag to
2670 // be considered, the sprm 6649 gives the level of the table
2671 sal_uInt8 nCellLevel
= 0;
2674 nCellLevel
= int(nullptr != m_xPlcxMan
->HasParaSprm(24).pSprm
);
2677 nCellLevel
= int(nullptr != m_xPlcxMan
->HasParaSprm(0x2416).pSprm
);
2679 nCellLevel
= int(nullptr != m_xPlcxMan
->HasParaSprm(0x244B).pSprm
);
2683 WW8_TablePos
*pTabPos
=nullptr;
2684 WW8_TablePos aTabPos
;
2685 if(nCellLevel
&& !m_bVer67
)
2687 WW8PLCFxSave1 aSave
;
2688 m_xPlcxMan
->GetPap()->Save( aSave
);
2690 WW8PLCFx_Cp_FKP
* pPap
= m_xPlcxMan
->GetPapPLCF();
2691 WW8_CP nMyStartCp
=nStartCp
;
2693 SprmResult aLevel
= m_xPlcxMan
->HasParaSprm(0x6649);
2694 if (aLevel
.pSprm
&& aLevel
.nRemainingData
>= 1)
2695 nCellLevel
= *aLevel
.pSprm
;
2697 bool bHasRowEnd
= SearchRowEnd(pPap
, nMyStartCp
, (m_nInTable
<nCellLevel
?m_nInTable
:nCellLevel
-1));
2699 // Bad Table, remain unchanged in level, e.g. #i19667#
2701 nCellLevel
= static_cast< sal_uInt8
>(m_nInTable
);
2703 if (bHasRowEnd
&& ParseTabPos(&aTabPos
,pPap
))
2706 m_xPlcxMan
->GetPap()->Restore( aSave
);
2709 // Then look if we are in an Apo
2711 ApoTestResults aApo
= TestApo(nCellLevel
, bTableRowEnd
, pTabPos
);
2713 // Look to see if we are in a Table, but Table in foot/end note not allowed
2714 bool bStartTab
= (m_nInTable
< nCellLevel
) && !m_bFootnoteEdn
;
2716 bool bStopTab
= m_bWasTabRowEnd
&& (m_nInTable
> nCellLevel
) && !m_bFootnoteEdn
;
2718 m_bWasTabRowEnd
= false; // must be deactivated right here to prevent next
2719 // WW8TabDesc::TableCellEnd() from making nonsense
2721 if (m_nInTable
&& !bTableRowEnd
&& !bStopTab
&& (m_nInTable
== nCellLevel
&& aApo
.HasStartStop()))
2722 bStopTab
= bStartTab
= true; // Required to stop and start table
2724 // Test for Anl (Numbering) and process all events in the right order
2725 if( m_bAnl
&& !bTableRowEnd
)
2727 SprmResult aSprm13
= m_xPlcxMan
->HasParaSprm(13);
2728 const sal_uInt8
* pSprm13
= aSprm13
.pSprm
;
2729 if (pSprm13
&& aSprm13
.nRemainingData
>= 1)
2730 { // Still Anl left?
2731 sal_uInt8 nT
= static_cast< sal_uInt8
>(GetNumType( *pSprm13
));
2732 if( ( nT
!= WW8_Pause
&& nT
!= m_nWwNumType
) // Anl change
2733 || aApo
.HasStartStop() // Forced Anl end
2734 || bStopTab
|| bStartTab
)
2736 StopAnlToRestart(nT
); // Anl-Restart (= change) over sprms
2740 NextAnlLine( pSprm13
); // Next Anl Line
2744 { // Regular Anl end
2745 StopAllAnl(); // Actual end
2757 m_aApos
[m_nInTable
] = false;
2760 if (aApo
.mbStartApo
)
2762 m_aApos
[m_nInTable
] = StartApo(aApo
, pTabPos
);
2763 // We need an ReSync after StartApo
2764 // (actually only if the Apo extends past a FKP border)
2769 WW8PLCFxSave1 aSave
;
2770 m_xPlcxMan
->GetPap()->Save( aSave
);
2772 // Numbering for cell borders causes a crash -> no Anls in Tables
2776 if(m_nInTable
< nCellLevel
)
2778 if (StartTable(nStartCp
))
2782 m_aApos
.push_back(false);
2785 if(m_nInTable
>= nCellLevel
)
2787 // We need an ReSync after StartTable
2788 // (actually only if the Apo extends past a FKP border)
2790 m_xPlcxMan
->GetPap()->Restore( aSave
);
2793 } while (!m_bFootnoteEdn
&& (m_nInTable
< nCellLevel
));
2794 return bTableRowEnd
;
2797 rtl_TextEncoding
SwWW8ImplReader::GetCharSetFromLanguage()
2801 The (default) character set used for a run of text is the default
2802 character set for the version of Word that last saved the document.
2804 This is a bit tentative, more might be required if the concept is correct.
2805 When later version of word write older 6/95 documents the charset is
2806 correctly set in the character runs involved, so it's hard to reproduce
2807 documents that require this to be sure of the process involved.
2809 const SvxLanguageItem
*pLang
= static_cast<const SvxLanguageItem
*>(GetFormatAttr(RES_CHRATR_LANGUAGE
));
2810 LanguageType eLang
= pLang
? pLang
->GetLanguage() : LANGUAGE_SYSTEM
;
2811 css::lang::Locale
aLocale(LanguageTag::convertToLocale(eLang
));
2812 return msfilter::util::getBestTextEncodingFromLocale(aLocale
);
2815 rtl_TextEncoding
SwWW8ImplReader::GetCJKCharSetFromLanguage()
2819 The (default) character set used for a run of text is the default
2820 character set for the version of Word that last saved the document.
2822 This is a bit tentative, more might be required if the concept is correct.
2823 When later version of word write older 6/95 documents the charset is
2824 correctly set in the character runs involved, so it's hard to reproduce
2825 documents that require this to be sure of the process involved.
2827 const SvxLanguageItem
*pLang
= static_cast<const SvxLanguageItem
*>(GetFormatAttr(RES_CHRATR_CJK_LANGUAGE
));
2828 LanguageType eLang
= pLang
? pLang
->GetLanguage() : LANGUAGE_SYSTEM
;
2829 css::lang::Locale
aLocale(LanguageTag::convertToLocale(eLang
));
2830 return msfilter::util::getBestTextEncodingFromLocale(aLocale
);
2833 rtl_TextEncoding
SwWW8ImplReader::GetCurrentCharSet()
2837 If the hard charset is set use it, if not see if there is an open
2838 character run that has set the charset, if not then fallback to the
2839 current underlying paragraph style.
2841 rtl_TextEncoding eSrcCharSet
= m_eHardCharSet
;
2842 if (eSrcCharSet
== RTL_TEXTENCODING_DONTKNOW
)
2845 eSrcCharSet
= GetCharSetFromLanguage();
2846 else if (!m_aFontSrcCharSets
.empty())
2847 eSrcCharSet
= m_aFontSrcCharSets
.top();
2848 if ((eSrcCharSet
== RTL_TEXTENCODING_DONTKNOW
) && m_nCharFormat
>= 0 && o3tl::make_unsigned(m_nCharFormat
) < m_vColl
.size() )
2849 eSrcCharSet
= m_vColl
[m_nCharFormat
].GetCharSet();
2850 if ((eSrcCharSet
== RTL_TEXTENCODING_DONTKNOW
) && StyleExists(m_nCurrentColl
) && m_nCurrentColl
< m_vColl
.size())
2851 eSrcCharSet
= m_vColl
[m_nCurrentColl
].GetCharSet();
2852 if (eSrcCharSet
== RTL_TEXTENCODING_DONTKNOW
)
2853 eSrcCharSet
= GetCharSetFromLanguage();
2858 //Takashi Ono for CJK
2859 rtl_TextEncoding
SwWW8ImplReader::GetCurrentCJKCharSet()
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
)
2870 if (!m_aFontSrcCJKCharSets
.empty())
2871 eSrcCharSet
= m_aFontSrcCJKCharSets
.top();
2872 if ((eSrcCharSet
== RTL_TEXTENCODING_DONTKNOW
) && m_nCharFormat
>= 0 && o3tl::make_unsigned(m_nCharFormat
) < m_vColl
.size() )
2873 eSrcCharSet
= m_vColl
[m_nCharFormat
].GetCJKCharSet();
2874 if (eSrcCharSet
== RTL_TEXTENCODING_DONTKNOW
&& StyleExists(m_nCurrentColl
) && m_nCurrentColl
< m_vColl
.size())
2875 eSrcCharSet
= m_vColl
[m_nCurrentColl
].GetCJKCharSet();
2876 if (eSrcCharSet
== RTL_TEXTENCODING_DONTKNOW
)
2877 eSrcCharSet
= GetCJKCharSetFromLanguage();
2882 void SwWW8ImplReader::PostProcessAttrs()
2884 if (m_pPostProcessAttrsInfo
== nullptr)
2887 SfxItemIter
aIter(m_pPostProcessAttrsInfo
->mItemSet
);
2889 for (const SfxPoolItem
* pItem
= aIter
.GetCurItem(); pItem
; pItem
= aIter
.NextItem())
2891 m_xCtrlStck
->NewAttr(*m_pPostProcessAttrsInfo
->mPaM
.GetPoint(),
2893 m_xCtrlStck
->SetAttr(*m_pPostProcessAttrsInfo
->mPaM
.GetMark(),
2897 m_pPostProcessAttrsInfo
.reset();
2902 It appears that some documents that are in a baltic 8 bit encoding which has
2903 some undefined characters can have use made of those characters, in which
2904 case they default to CP1252. If not then it's perhaps that the font encoding
2905 is only in use for 6/7 and for 8+ if we are in 8bit mode then the encoding
2908 So an encoding converter that on an undefined character attempts to
2909 convert from 1252 on the undefined character
2911 static std::size_t Custom8BitToUnicode(rtl_TextToUnicodeConverter hConverter
,
2912 char const *pIn
, std::size_t nInLen
, sal_Unicode
*pOut
, std::size_t nOutLen
)
2914 const sal_uInt32 nFlags
=
2915 RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
|
2916 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
|
2917 RTL_TEXTTOUNICODE_FLAGS_INVALID_IGNORE
|
2918 RTL_TEXTTOUNICODE_FLAGS_FLUSH
;
2920 const sal_uInt32 nFlags2
=
2921 RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_IGNORE
|
2922 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_IGNORE
|
2923 RTL_TEXTTOUNICODE_FLAGS_INVALID_IGNORE
|
2924 RTL_TEXTTOUNICODE_FLAGS_FLUSH
;
2926 std::size_t nDestChars
=0;
2927 std::size_t nConverted
=0;
2931 sal_uInt32 nInfo
= 0;
2932 sal_Size nThisConverted
=0;
2934 nDestChars
+= rtl_convertTextToUnicode(hConverter
, nullptr,
2935 pIn
+nConverted
, nInLen
-nConverted
,
2936 pOut
+nDestChars
, nOutLen
-nDestChars
,
2937 nFlags
, &nInfo
, &nThisConverted
);
2939 OSL_ENSURE(nInfo
== 0, "A character conversion failed!");
2941 nConverted
+= nThisConverted
;
2944 nInfo
& RTL_TEXTTOUNICODE_INFO_UNDEFINED
||
2945 nInfo
& RTL_TEXTTOUNICODE_INFO_MBUNDEFINED
2948 sal_Size nOtherConverted
;
2949 rtl_TextToUnicodeConverter hCP1252Converter
=
2950 rtl_createTextToUnicodeConverter(RTL_TEXTENCODING_MS_1252
);
2951 nDestChars
+= rtl_convertTextToUnicode(hCP1252Converter
, nullptr,
2953 pOut
+nDestChars
, nOutLen
-nDestChars
,
2954 nFlags2
, &nInfo
, &nOtherConverted
);
2955 rtl_destroyTextToUnicodeConverter(hCP1252Converter
);
2958 } while (nConverted
< nInLen
);
2963 bool SwWW8ImplReader::LangUsesHindiNumbers(LanguageType nLang
)
2965 bool bResult
= false;
2967 switch (static_cast<sal_uInt16
>(nLang
))
2969 case 0x1401: // Arabic(Algeria)
2970 case 0x3c01: // Arabic(Bahrain)
2971 case 0xc01: // Arabic(Egypt)
2972 case 0x801: // Arabic(Iraq)
2973 case 0x2c01: // Arabic (Jordan)
2974 case 0x3401: // Arabic(Kuwait)
2975 case 0x3001: // Arabic(Lebanon)
2976 case 0x1001: // Arabic(Libya)
2977 case 0x1801: // Arabic(Morocco)
2978 case 0x2001: // Arabic(Oman)
2979 case 0x4001: // Arabic(Qatar)
2980 case 0x401: // Arabic(Saudi Arabia)
2981 case 0x2801: // Arabic(Syria)
2982 case 0x1c01: // Arabic(Tunisia)
2983 case 0x3801: // Arabic(U.A.E)
2984 case 0x2401: // Arabic(Yemen)
2994 sal_Unicode
SwWW8ImplReader::TranslateToHindiNumbers(sal_Unicode nChar
)
2996 if (nChar
>= 0x0030 && nChar
<= 0x0039)
2997 return nChar
+ 0x0630;
3004 OUString
makeOUString(rtl_uString
*pStr
, sal_Int32 nAllocLen
)
3006 //if read len was in or around that of allocated len, just reuse pStr
3007 if (nAllocLen
< pStr
->length
+ 256)
3008 return OUString(pStr
, SAL_NO_ACQUIRE
);
3009 //otherwise copy the shorter used section to release extra mem
3010 OUString
sRet(pStr
->buffer
, pStr
->length
);
3011 rtl_uString_release(pStr
);
3017 * Return value: true for non special chars
3019 bool SwWW8ImplReader::ReadPlainChars(WW8_CP
& rPos
, sal_Int32 nEnd
, sal_Int32 nCpOfs
)
3021 sal_Int32 nRequestedStrLen
= nEnd
- rPos
;
3023 OSL_ENSURE(nRequestedStrLen
, "String is 0");
3024 if (nRequestedStrLen
<= 0)
3028 const bool bFail
= o3tl::checked_add(nCpOfs
, rPos
, nCp
);
3031 rPos
+=nRequestedStrLen
;
3035 sal_Int32 nRequestedPos
= m_xSBase
->WW8Cp2Fc(nCp
, &m_bIsUnicode
);
3036 bool bValidPos
= checkSeek(*m_pStrm
, nRequestedPos
);
3037 OSL_ENSURE(bValidPos
, "Document claimed to have more text than available");
3040 // Swallow missing range, e.g. #i95550#
3041 rPos
+=nRequestedStrLen
;
3045 std::size_t nAvailableStrLen
= m_pStrm
->remainingSize() / (m_bIsUnicode
? 2 : 1);
3046 OSL_ENSURE(nAvailableStrLen
, "Document claimed to have more text than available");
3047 if (!nAvailableStrLen
)
3049 // Swallow missing range, e.g. #i95550#
3050 rPos
+=nRequestedStrLen
;
3054 sal_Int32 nValidStrLen
= std::min
<std::size_t>(nRequestedStrLen
, nAvailableStrLen
);
3056 // Reset Unicode flag and correct FilePos if needed.
3057 // Note: Seek is not expensive, as we're checking inline whether or not
3058 // the correct FilePos has already been reached.
3059 const sal_Int32 nStrLen
= std::min(nValidStrLen
, SAL_MAX_INT32
-1);
3061 rtl_TextEncoding eSrcCharSet
= m_bVer67
? GetCurrentCharSet() :
3062 RTL_TEXTENCODING_MS_1252
;
3063 if (m_bVer67
&& eSrcCharSet
== RTL_TEXTENCODING_MS_932
)
3068 Older documents exported as word 95 that use unicode aware fonts will
3069 have the charset of those fonts set to RTL_TEXTENCODING_MS_932 on
3070 export as the conversion from RTL_TEXTENCODING_UNICODE. This is a serious
3073 We will try and use a fallback encoding if the conversion from
3074 RTL_TEXTENCODING_MS_932 fails, but you can get unlucky and get a document
3075 which isn't really in RTL_TEXTENCODING_MS_932 but parts of it form
3076 valid RTL_TEXTENCODING_MS_932 by chance :-(
3078 We're not the only ones that struggle with this: Here's the help from
3079 MSOffice 2003 on the topic:
3082 Earlier versions of Microsoft Word were sometimes used in conjunction with
3083 third-party language-processing add-in programs designed to support Chinese or
3084 Korean on English versions of Microsoft Windows. Use of these add-ins sometimes
3085 results in incorrect text display in more recent versions of Word.
3087 However, you can set options to convert these documents so that text is
3088 displayed correctly. On the Tools menu, click Options, and then click the
3089 General tab. In the English Word 6.0/95 documents list, select Contain Asian
3090 text (to have Word interpret the text as Asian code page data, regardless of
3091 its font) or Automatically detect Asian text (to have Word attempt to determine
3092 which parts of the text are meant to be Asian).
3095 What we can try here is to ignore a RTL_TEXTENCODING_MS_932 codepage if
3096 the language is not Japanese
3099 const SfxPoolItem
* pItem
= GetFormatAttr(RES_CHRATR_CJK_LANGUAGE
);
3100 if (pItem
!= nullptr && LANGUAGE_JAPANESE
!= static_cast<const SvxLanguageItem
*>(pItem
)->GetLanguage())
3102 SAL_WARN("sw.ww8", "discarding word95 RTL_TEXTENCODING_MS_932 encoding");
3103 eSrcCharSet
= GetCharSetFromLanguage();
3106 const rtl_TextEncoding eSrcCJKCharSet
= m_bVer67
? GetCurrentCJKCharSet() :
3107 RTL_TEXTENCODING_MS_1252
;
3109 // allocate unicode string data
3110 auto l
= [](rtl_uString
* p
){rtl_uString_release(p
);};
3111 std::unique_ptr
<rtl_uString
, decltype(l
)> xStr(rtl_uString_alloc(nStrLen
), l
);
3112 sal_Unicode
* pBuffer
= xStr
->buffer
;
3113 sal_Unicode
* pWork
= pBuffer
;
3115 std::unique_ptr
<char[]> p8Bits
;
3117 rtl_TextToUnicodeConverter hConverter
= nullptr;
3118 if (!m_bIsUnicode
|| m_bVer67
)
3119 hConverter
= rtl_createTextToUnicodeConverter(eSrcCharSet
);
3122 p8Bits
.reset( new char[nStrLen
] );
3124 // read the stream data
3125 sal_uInt8 nBCode
= 0;
3128 LanguageType nCTLLang
= LANGUAGE_SYSTEM
;
3129 const SfxPoolItem
* pItem
= GetFormatAttr(RES_CHRATR_CTL_LANGUAGE
);
3130 if (pItem
!= nullptr)
3131 nCTLLang
= static_cast<const SvxLanguageItem
*>(pItem
)->GetLanguage();
3134 for (nL2
= 0; nL2
< nStrLen
; ++nL2
)
3137 m_pStrm
->ReadUInt16( nUCode
); // unicode --> read 2 bytes
3140 m_pStrm
->ReadUChar( nBCode
); // old code --> read 1 byte
3144 if (!m_pStrm
->good())
3146 rPos
= WW8_CP_MAX
-10; // -> eof or other error
3150 if ((32 > nUCode
) || (0xa0 == nUCode
))
3152 m_pStrm
->SeekRel( m_bIsUnicode
? -2 : -1 );
3153 break; // Special character < 32, == 0xa0 found
3162 if (nUCode
>= 0x3000) //0x8000 ?
3165 aTest
[0] = static_cast< char >((nUCode
& 0xFF00) >> 8);
3166 aTest
[1] = static_cast< char >(nUCode
& 0x00FF);
3167 OUString
aTemp(aTest
, 2, eSrcCJKCharSet
);
3168 OSL_ENSURE(aTemp
.getLength() == 1, "so much for that theory");
3169 *pWork
++ = aTemp
[0];
3173 char cTest
= static_cast< char >(nUCode
& 0x00FF);
3174 pWork
+= Custom8BitToUnicode(hConverter
, &cTest
, 1, pWork
, 1);
3179 p8Bits
[nL2
] = nBCode
;
3184 const sal_Int32 nEndUsed
= !m_bIsUnicode
3185 ? Custom8BitToUnicode(hConverter
, p8Bits
.get(), nL2
, pBuffer
, nStrLen
)
3188 if (m_bRegardHindiDigits
&& m_bBidi
&& LangUsesHindiNumbers(nCTLLang
))
3190 for (sal_Int32 nI
= 0; nI
< nEndUsed
; ++nI
, ++pBuffer
)
3191 *pBuffer
= TranslateToHindiNumbers(*pBuffer
);
3194 xStr
->buffer
[nEndUsed
] = 0;
3195 xStr
->length
= nEndUsed
;
3197 emulateMSWordAddTextToParagraph(makeOUString(xStr
.release(), nStrLen
));
3199 if (!m_aApos
.back()) // a para end in apo doesn't count
3200 m_bWasParaEnd
= false; // No CR
3204 rtl_destroyTextToUnicodeConverter(hConverter
);
3205 return nL2
>= nStrLen
;
3208 #define MSASCII SAL_MAX_INT16
3212 // We want to force weak chars inside 0x0020 to 0x007F to LATIN
3213 sal_Int16
lcl_getScriptType(
3214 const uno::Reference
<i18n::XBreakIterator
>& rBI
,
3215 const OUString
&rString
, sal_Int32 nPos
)
3217 sal_Int16 nScript
= rBI
->getScriptType(rString
, nPos
);
3218 if (nScript
== i18n::ScriptType::WEAK
&& rString
[nPos
] >= 0x0020 && rString
[nPos
] <= 0x007F)
3223 // We want to know about WEAK segments, so endOfScript isn't
3224 // useful, and see lcl_getScriptType anyway
3225 sal_Int32
lcl_endOfScript(
3226 const uno::Reference
<i18n::XBreakIterator
>& rBI
,
3227 const OUString
&rString
, sal_Int32 nPos
, sal_Int16 nScript
)
3229 while (nPos
< rString
.getLength())
3231 sal_Int16 nNewScript
= lcl_getScriptType(rBI
, rString
, nPos
);
3232 if (nScript
!= nNewScript
)
3239 sal_Int32
lcl_getWriterScriptType(
3240 const uno::Reference
<i18n::XBreakIterator
>& rBI
,
3241 const OUString
&rString
, sal_Int32 nPos
)
3243 sal_Int16 nScript
= i18n::ScriptType::WEAK
;
3245 if (rString
.isEmpty())
3250 nScript
= rBI
->getScriptType(rString
, nPos
);
3251 if (nScript
!= i18n::ScriptType::WEAK
)
3259 bool samePitchIgnoreUnknown(FontPitch eA
, FontPitch eB
)
3261 return (eA
== eB
|| eA
== PITCH_DONTKNOW
|| eB
== PITCH_DONTKNOW
);
3264 bool sameFontIgnoringIrrelevantFields(const SvxFontItem
&rA
, const SvxFontItem
&rB
)
3266 // Ignoring CharSet, and ignoring unknown pitch
3267 return rA
.GetFamilyName() == rB
.GetFamilyName() &&
3268 rA
.GetStyleName() == rB
.GetStyleName() &&
3269 rA
.GetFamily() == rB
.GetFamily() &&
3270 samePitchIgnoreUnknown(rA
.GetPitch(), rB
.GetPitch());
3274 // In writer we categorize text into CJK, CTL and "Western" for everything else.
3275 // Microsoft Word basically categorizes text into East Asian, Complex, ASCII,
3276 // NonEastAsian/HighAnsi, with some shared characters and some properties to
3277 // hint as to which way to bias those shared characters.
3279 // That's four categories, we however have three categories. Given that problem
3280 // here we would ideally find out "what would word do" to see what font/language
3281 // word would assign to characters based on the unicode range they fall into and
3282 // hack the word one onto the range we use. However it's unclear what word's
3283 // categorization is. So we don't do that here yet.
3285 // Additional to the categorization, when word encounters weak text for ambiguous
3286 // chars it uses idcthint to indicate which way to bias. We don't have an idcthint
3287 // feature in writer.
3289 // So what we currently do here then is to split our text into non-weak/weak
3290 // sections and uses word's idcthint to determine what font it would use and
3291 // force that on for the segment. Following what we *do* know about word's
3292 // categorization, we know that the range 0x0020 and 0x007F is sprmCRgFtc0 in
3293 // word, something we map to LATIN, so we consider all weak chars in that range
3294 // to auto-bias to LATIN.
3296 // See https://bugs.libreoffice.org/show_bug.cgi?id=34319 for an example
3297 void SwWW8ImplReader::emulateMSWordAddTextToParagraph(const OUString
& rAddString
)
3299 if (rAddString
.isEmpty())
3304 simpleAddTextToParagraph(rAddString
);
3308 uno::Reference
<i18n::XBreakIterator
> xBI(g_pBreakIt
->GetBreakIter());
3311 sal_Int16 nScript
= lcl_getScriptType(xBI
, rAddString
, 0);
3312 sal_Int32 nLen
= rAddString
.getLength();
3314 OUString sParagraphText
;
3315 const SwContentNode
*pCntNd
= m_pPaM
->GetPointContentNode();
3316 const SwTextNode
* pNd
= pCntNd
? pCntNd
->GetTextNode() : nullptr;
3318 sParagraphText
= pNd
->GetText();
3319 sal_Int32 nParaOffset
= sParagraphText
.getLength();
3320 sParagraphText
= sParagraphText
+ rAddString
;
3325 sal_Int32 nEnd
= lcl_endOfScript(xBI
, rAddString
, nPos
, nScript
);
3329 OUString
sChunk(rAddString
.copy(nPos
, nEnd
-nPos
));
3330 const sal_uInt16 aIds
[] = {RES_CHRATR_FONT
, RES_CHRATR_CJK_FONT
, RES_CHRATR_CTL_FONT
};
3331 const SvxFontItem
*pOverriddenItems
[] = {nullptr, nullptr, nullptr};
3332 bool aForced
[] = {false, false, false};
3334 int nLclIdctHint
= 0xFF;
3335 if (nScript
== i18n::ScriptType::WEAK
)
3337 const SfxInt16Item
*pIdctHint
= static_cast<const SfxInt16Item
*>(GetFormatAttr(RES_CHRATR_IDCTHINT
));
3338 nLclIdctHint
= pIdctHint
->GetValue();
3340 else if (nScript
== MSASCII
) // Force weak chars in ascii range to use LATIN font
3343 sal_uInt16 nForceFromFontId
= 0;
3344 if (nLclIdctHint
!= 0xFF)
3346 switch (nLclIdctHint
)
3349 nForceFromFontId
= RES_CHRATR_FONT
;
3352 nForceFromFontId
= RES_CHRATR_CJK_FONT
;
3355 nForceFromFontId
= RES_CHRATR_CTL_FONT
;
3362 if (nForceFromFontId
!= 0)
3364 // Now we know that word would use the nForceFromFontId font for this range
3365 // Try and determine what script writer would assign this range to
3367 sal_Int32 nWriterScript
= lcl_getWriterScriptType(xBI
, sParagraphText
,
3368 nPos
+ nParaOffset
);
3370 bool bWriterWillUseSameFontAsWordAutomatically
= false;
3372 if (nWriterScript
!= i18n::ScriptType::WEAK
)
3375 (nWriterScript
== i18n::ScriptType::ASIAN
&& nForceFromFontId
== RES_CHRATR_CJK_FONT
) ||
3376 (nWriterScript
== i18n::ScriptType::COMPLEX
&& nForceFromFontId
== RES_CHRATR_CTL_FONT
) ||
3377 (nWriterScript
== i18n::ScriptType::LATIN
&& nForceFromFontId
== RES_CHRATR_FONT
)
3380 bWriterWillUseSameFontAsWordAutomatically
= true;
3384 const SvxFontItem
*pSourceFont
= static_cast<const SvxFontItem
*>(GetFormatAttr(nForceFromFontId
));
3385 sal_uInt16 nDestId
= aIds
[nWriterScript
-1];
3386 const SvxFontItem
*pDestFont
= static_cast<const SvxFontItem
*>(GetFormatAttr(nDestId
));
3387 bWriterWillUseSameFontAsWordAutomatically
= sameFontIgnoringIrrelevantFields(*pSourceFont
, *pDestFont
);
3391 // Writer won't use the same font as word, so force the issue
3392 if (!bWriterWillUseSameFontAsWordAutomatically
)
3394 const SvxFontItem
*pSourceFont
= static_cast<const SvxFontItem
*>(GetFormatAttr(nForceFromFontId
));
3396 for (size_t i
= 0; i
< SAL_N_ELEMENTS(aIds
); ++i
)
3398 const SvxFontItem
*pDestFont
= static_cast<const SvxFontItem
*>(GetFormatAttr(aIds
[i
]));
3399 aForced
[i
] = aIds
[i
] != nForceFromFontId
&& *pSourceFont
!= *pDestFont
;
3402 pOverriddenItems
[i
] =
3403 static_cast<const SvxFontItem
*>(m_xCtrlStck
->GetStackAttr(*m_pPaM
->GetPoint(), aIds
[i
]));
3405 SvxFontItem
aForceFont(*pSourceFont
);
3406 aForceFont
.SetWhich(aIds
[i
]);
3407 m_xCtrlStck
->NewAttr(*m_pPaM
->GetPoint(), aForceFont
);
3413 simpleAddTextToParagraph(sChunk
);
3415 for (size_t i
= 0; i
< SAL_N_ELEMENTS(aIds
); ++i
)
3419 m_xCtrlStck
->SetAttr(*m_pPaM
->GetPoint(), aIds
[i
]);
3420 if (pOverriddenItems
[i
])
3421 m_xCtrlStck
->NewAttr(*m_pPaM
->GetPoint(), *(pOverriddenItems
[i
]));
3427 nScript
= lcl_getScriptType(xBI
, rAddString
, nPos
);
3433 auto FilterControlChars(std::u16string_view aString
) -> OUString
3435 OUStringBuffer
buf(aString
.size());
3436 for (size_t i
= 0; i
< aString
.size(); ++i
)
3438 sal_Unicode
const ch(aString
[i
]);
3439 if (!linguistic::IsControlChar(ch
) || ch
== '\r' || ch
== '\n' || ch
== '\t')
3445 SAL_INFO("sw.ww8", "filtering control character");
3448 return buf
.makeStringAndClear();
3453 void SwWW8ImplReader::simpleAddTextToParagraph(std::u16string_view aAddString
)
3455 OUString
const addString(sw::FilterControlChars(aAddString
));
3457 if (addString
.isEmpty())
3460 const SwContentNode
*pCntNd
= m_pPaM
->GetPointContentNode();
3461 const SwTextNode
* pNd
= pCntNd
? pCntNd
->GetTextNode() : nullptr;
3463 OSL_ENSURE(pNd
, "What the hell, where's my text node");
3468 const sal_Int32 nCharsLeft
= SAL_MAX_INT32
- pNd
->GetText().getLength();
3471 if (addString
.getLength() <= nCharsLeft
)
3473 m_rDoc
.getIDocumentContentOperations().InsertString(*m_pPaM
, addString
);
3477 m_rDoc
.getIDocumentContentOperations().InsertString(*m_pPaM
, addString
.copy(0, nCharsLeft
));
3478 AppendTextNode(*m_pPaM
->GetPoint());
3479 m_rDoc
.getIDocumentContentOperations().InsertString(*m_pPaM
, addString
.copy(nCharsLeft
));
3484 AppendTextNode(*m_pPaM
->GetPoint());
3485 m_rDoc
.getIDocumentContentOperations().InsertString(*m_pPaM
, addString
);
3488 m_bReadTable
= false;
3492 * Return value: true for para end
3494 bool SwWW8ImplReader::ReadChars(WW8_CP
& rPos
, WW8_CP nNextAttr
, tools::Long nTextEnd
,
3497 tools::Long nEnd
= ( nNextAttr
< nTextEnd
) ? nNextAttr
: nTextEnd
;
3499 if (m_bSymbol
|| m_bIgnoreText
)
3501 WW8_CP nRequested
= nEnd
- rPos
;
3502 if (m_bSymbol
) // Insert special chars
3504 sal_uInt64 nMaxPossible
= m_pStrm
->remainingSize();
3505 if (o3tl::make_unsigned(nRequested
) > nMaxPossible
)
3507 SAL_WARN("sw.ww8", "document claims to have more characters, " << nRequested
<< " than remaining, " << nMaxPossible
);
3508 nRequested
= nMaxPossible
;
3511 if (!linguistic::IsControlChar(m_cSymbol
)
3512 || m_cSymbol
== '\r' || m_cSymbol
== '\n' || m_cSymbol
== '\t')
3514 for (WW8_CP nCh
= 0; nCh
< nRequested
; ++nCh
)
3516 m_rDoc
.getIDocumentContentOperations().InsertString(*m_pPaM
, OUString(m_cSymbol
));
3518 m_xCtrlStck
->SetAttr(*m_pPaM
->GetPoint(), RES_CHRATR_FONT
);
3519 m_xCtrlStck
->SetAttr(*m_pPaM
->GetPoint(), RES_CHRATR_CJK_FONT
);
3520 m_xCtrlStck
->SetAttr(*m_pPaM
->GetPoint(), RES_CHRATR_CTL_FONT
);
3523 m_pStrm
->SeekRel(nRequested
);
3524 rPos
= nEnd
; // Ignore until attribute end
3530 if (ReadPlainChars(rPos
, nEnd
, nCpOfs
))
3531 return false; // Done
3533 bool bStartLine
= ReadChar(rPos
, nCpOfs
);
3535 if (m_bPgSecBreak
|| bStartLine
|| rPos
== nEnd
) // CR or Done
3542 bool SwWW8ImplReader::HandlePageBreakChar()
3544 bool bParaEndAdded
= false;
3545 // #i1909# section/page breaks should not occur in tables, word
3546 // itself ignores them in this case.
3550 SwTextNode
* pTemp
= m_pPaM
->GetPointNode().GetTextNode();
3551 if (pTemp
&& pTemp
->GetText().isEmpty()
3552 && (m_bFirstPara
|| m_bFirstParaOfPage
))
3555 AppendTextNode(*m_pPaM
->GetPoint());
3556 pTemp
->SetAttr(*GetDfltAttr(RES_PARATR_NUMRULE
));
3559 m_bPgSecBreak
= true;
3560 m_xCtrlStck
->KillUnlockedAttrs(*m_pPaM
->GetPoint());
3562 If it's a 0x0c without a paragraph end before it, act like a
3563 paragraph end, but nevertheless, numbering (and perhaps other
3564 similar constructs) do not exist on the para.
3566 if (!m_bWasParaEnd
&& IsTemp
)
3568 bParaEndAdded
= true;
3569 if (0 >= m_pPaM
->GetPoint()->GetContentIndex())
3571 if (SwTextNode
* pTextNode
= m_pPaM
->GetPointNode().GetTextNode())
3574 *GetDfltAttr(RES_PARATR_NUMRULE
));
3579 return bParaEndAdded
;
3582 bool SwWW8ImplReader::ReadChar(tools::Long nPosCp
, tools::Long nCpOfs
)
3584 bool bNewParaEnd
= false;
3585 // Reset Unicode flag and correct FilePos if needed.
3586 // Note: Seek is not expensive, as we're checking inline whether or not
3587 // the correct FilePos has already been reached.
3588 std::size_t nRequestedPos
= m_xSBase
->WW8Cp2Fc(nCpOfs
+nPosCp
, &m_bIsUnicode
);
3589 if (!checkSeek(*m_pStrm
, nRequestedPos
))
3592 sal_uInt16
nWCharVal(0);
3594 m_pStrm
->ReadUInt16( nWCharVal
); // unicode --> read 2 bytes
3597 sal_uInt8
nBCode(0);
3598 m_pStrm
-> ReadUChar( nBCode
); // old code --> read 1 byte
3602 sal_Unicode cInsert
= '\x0';
3603 bool bParaMark
= false;
3605 if ( 0xc != nWCharVal
)
3606 m_bFirstParaOfPage
= false;
3614 SwPageNumberField
aField(
3615 static_cast<SwPageNumberFieldType
*>(m_rDoc
.getIDocumentFieldsAccess().GetSysFieldType(
3616 SwFieldIds::PageNumber
)), PG_RANDOM
, SVX_NUM_ARABIC
);
3617 m_rDoc
.getIDocumentContentOperations().InsertPoolItem(*m_pPaM
, SwFormatField(aField
));
3621 // extremely slow, so skip for fuzzing, and insert a space instead
3626 // if there is only one column word treats a column break like a pagebreak.
3627 if (m_aSectionManager
.CurrentSectionColCount() < 2)
3628 bParaMark
= HandlePageBreakChar();
3629 else if (!m_nInTable
)
3631 // Always insert a txtnode for a column break, e.g. ##
3632 SwContentNode
*pCntNd
=m_pPaM
->GetPointContentNode();
3633 if (pCntNd
!=nullptr && pCntNd
->Len()>0) // if par is empty not break is needed
3634 AppendTextNode(*m_pPaM
->GetPoint());
3635 m_rDoc
.getIDocumentContentOperations().InsertPoolItem(*m_pPaM
, SvxFormatBreakItem(SvxBreak::ColumnBefore
, RES_BREAK
));
3641 WW8PLCFxDesc
* pPap
= m_xPlcxMan
->GetPap();
3642 //The last paragraph of each cell is terminated by a special
3643 //paragraph mark called a cell mark. Following the cell mark
3644 //that ends the last cell of a table row, the table row is
3645 //terminated by a special paragraph mark called a row mark
3647 //So the 0x7 should be right at the end of the previous
3648 //range to be a real cell-end.
3649 if (pPap
->nOrigStartPos
== nPosCp
+1 ||
3650 pPap
->nOrigStartPos
== WW8_CP_MAX
)
3652 TabCellEnd(); // Table cell/row end
3659 if( !m_bSpec
) // "Satellite"
3660 cInsert
= u
'\x00a4';
3663 if( !m_bSpec
) // "Para End" char
3664 cInsert
= u
'\x00b5';
3665 //TODO: should this be U+00B6 PILCROW SIGN rather than
3666 // U+00B5 MICRO SIGN?
3669 if( !m_bSpec
) // Juristenparagraph
3671 cp_set::iterator aItr
= m_aTOXEndCps
.find(static_cast<WW8_CP
>(nPosCp
));
3672 if (aItr
== m_aTOXEndCps
.end())
3673 cInsert
= u
'\x00a7';
3675 m_aTOXEndCps
.erase(aItr
);
3679 cInsert
= '\x9'; // Tab
3682 cInsert
= '\xa'; // Hard NewLine
3685 bParaMark
= HandlePageBreakChar();
3687 case 0x1e: // Non-breaking hyphen
3688 m_rDoc
.getIDocumentContentOperations().InsertString( *m_pPaM
, OUString(CHAR_HARDHYPHEN
) );
3690 case 0x1f: // Non-required hyphens
3691 m_rDoc
.getIDocumentContentOperations().InsertString( *m_pPaM
, OUString(CHAR_SOFTHYPHEN
) );
3693 case 0xa0: // Non-breaking spaces
3694 m_rDoc
.getIDocumentContentOperations().InsertString( *m_pPaM
, OUString(CHAR_HARDBLANK
) );
3698 Current thinking is that if bObj is set then we have a
3699 straightforward "traditional" ole object, otherwise we have a
3700 graphic preview of an associated ole2 object (or a simple
3703 normally in the canvas field, the code is 0x8 0x1.
3704 in a special case, the code is 0x1 0x1, which yields a simple picture
3707 bool bReadObj
= IsInlineEscherHack();
3710 sal_uInt64 nCurPos
= m_pStrm
->Tell();
3711 sal_uInt16
nWordCode(0);
3714 m_pStrm
->ReadUInt16( nWordCode
);
3717 sal_uInt8
nByteCode(0);
3718 m_pStrm
->ReadUChar( nByteCode
);
3719 nWordCode
= nByteCode
;
3721 if( nWordCode
== 0x1 )
3723 m_pStrm
->Seek( nCurPos
);
3727 SwFrameFormat
*pResult
= nullptr;
3729 pResult
= ImportOle();
3732 SwFrameFormat
* pAsCharFlyFormat
=
3733 m_rDoc
.MakeFrameFormat(OUString(), m_rDoc
.GetDfltFrameFormat());
3734 SwFormatAnchor
aAnchor(RndStdIds::FLY_AS_CHAR
);
3735 pAsCharFlyFormat
->SetFormatAttr(aAnchor
);
3736 pResult
= ImportGraf(nullptr, pAsCharFlyFormat
);
3737 m_rDoc
.DelFrameFormat(pAsCharFlyFormat
);
3741 // If we have a bad 0x1 insert a space instead.
3745 OSL_ENSURE(!m_bObj
&& !m_bEmbeddObj
&& !m_nObjLocFc
,
3746 "WW8: Please report this document, it may have a "
3752 m_bObj
= m_bEmbeddObj
= false;
3760 Read_GrafLayer( nPosCp
);
3763 bNewParaEnd
= bParaMark
= true;
3768 Yes complex, if there is an entry in the undocumented PLCF
3769 which I believe to be a record of cell and row boundaries
3770 see if the magic bit which I believe to mean cell end is
3771 set. I also think btw that the third byte of the 4 byte
3772 value is the level of the cell
3774 WW8PLCFspecial
* pTest
= m_xPlcxMan
->GetMagicTables();
3775 if (pTest
&& pTest
->SeekPosExact(nPosCp
+1+nCpOfs
) &&
3776 pTest
->Where() == nPosCp
+1+nCpOfs
)
3780 sal_uInt32 nData
= pTest
->Get(nPos
, pData
) ? SVBT32ToUInt32(*static_cast<SVBT32
*>(pData
))
3782 if (nData
& 0x2) // Might be how it works
3788 // tdf#106799: We expect TTP marks to be also cell marks,
3789 // but sometimes sprmPFInnerTtp comes without sprmPFInnerTableCell
3790 else if (m_bWasTabCellEnd
|| m_bWasTabRowEnd
)
3797 m_bWasTabCellEnd
= false;
3800 case 0x5: // Annotation reference
3803 case 0x2: // TODO: Auto-Footnote-Number, should be replaced by SwWW8ImplReader::End_Footnote later
3804 if (!m_aFootnoteStack
.empty())
3808 SAL_INFO( "sw.ww8.level2", "<unknownValue val=\"" << nWCharVal
<< "\">" );
3812 if( '\x0' != cInsert
)
3814 OUString
sInsert(cInsert
);
3815 emulateMSWordAddTextToParagraph(sInsert
);
3817 if (!m_aApos
.back()) // a para end in apo doesn't count
3818 m_bWasParaEnd
= bNewParaEnd
;
3822 void SwWW8ImplReader::ProcessCurrentCollChange(WW8PLCFManResult
& rRes
,
3823 bool* pStartAttr
, bool bCallProcessSpecial
)
3825 sal_uInt16 nOldColl
= m_nCurrentColl
;
3826 m_nCurrentColl
= m_xPlcxMan
->GetColl();
3829 if (m_nCurrentColl
>= m_vColl
.size() || !m_vColl
[m_nCurrentColl
].m_pFormat
|| !m_vColl
[m_nCurrentColl
].m_bColl
)
3832 m_bParaAutoBefore
= false;
3833 m_bParaAutoAfter
= false;
3837 m_bParaAutoBefore
= m_vColl
[m_nCurrentColl
].m_bParaAutoBefore
;
3838 m_bParaAutoAfter
= m_vColl
[m_nCurrentColl
].m_bParaAutoAfter
;
3841 if (nOldColl
>= m_vColl
.size())
3842 nOldColl
= 0; // guess! TODO make sure this is what we want
3844 bool bTabRowEnd
= false;
3845 if( pStartAttr
&& bCallProcessSpecial
&& !m_bInHyperlink
)
3848 // Frame/Table/Autonumbering List Level
3849 bTabRowEnd
= ProcessSpecial(bReSync
, rRes
.nCurrentCp
+ m_xPlcxMan
->GetCpOfs());
3851 *pStartAttr
= m_xPlcxMan
->Get( &rRes
); // Get Attribute-Pos again
3854 if (!bTabRowEnd
&& StyleExists(m_nCurrentColl
))
3856 SetTextFormatCollAndListLevel( *m_pPaM
, m_vColl
[ m_nCurrentColl
]);
3857 ChkToggleAttr(m_vColl
[ nOldColl
].m_n81Flags
, m_vColl
[ m_nCurrentColl
].m_n81Flags
);
3858 ChkToggleBiDiAttr(m_vColl
[nOldColl
].m_n81BiDiFlags
,
3859 m_vColl
[m_nCurrentColl
].m_n81BiDiFlags
);
3863 tools::Long
SwWW8ImplReader::ReadTextAttr(WW8_CP
& rTextPos
, tools::Long nTextEnd
, bool& rbStartLine
, int nDepthGuard
)
3865 tools::Long nSkipChars
= 0;
3866 WW8PLCFManResult aRes
;
3868 OSL_ENSURE(m_pPaM
->GetPointNode().GetTextNode(), "Missing txtnode");
3869 bool bStartAttr
= m_xPlcxMan
->Get(&aRes
); // Get Attribute position again
3870 aRes
.nCurrentCp
= rTextPos
; // Current Cp position
3872 bool bNewSection
= (aRes
.nFlags
& MAN_MASK_NEW_SEP
) && !m_bIgnoreText
;
3873 if ( bNewSection
) // New Section
3875 OSL_ENSURE(m_pPaM
->GetPointNode().GetTextNode(), "Missing txtnode");
3876 // Create PageDesc and fill it
3877 m_aSectionManager
.CreateSep(rTextPos
);
3878 // -> 0xc was a Sectionbreak, but not a Pagebreak;
3879 // Create PageDesc and fill it
3880 m_bPgSecBreak
= false;
3881 OSL_ENSURE(m_pPaM
->GetPointNode().GetTextNode(), "Missing txtnode");
3884 // New paragraph over Plcx.Fkp.papx
3885 if ( (aRes
.nFlags
& MAN_MASK_NEW_PAP
)|| rbStartLine
)
3887 ProcessCurrentCollChange( aRes
, &bStartAttr
,
3888 MAN_MASK_NEW_PAP
== (aRes
.nFlags
& MAN_MASK_NEW_PAP
) &&
3890 rbStartLine
= false;
3893 // position of last CP that's to be ignored
3894 tools::Long nSkipPos
= -1;
3896 if( 0 < aRes
.nSprmId
) // Ignore empty Attrs
3898 if( ( eFTN
> aRes
.nSprmId
) || ( 0x0800 <= aRes
.nSprmId
) )
3900 if( bStartAttr
) // WW attributes
3902 if( aRes
.nMemLen
>= 0 )
3903 ImportSprm(aRes
.pMemPos
, aRes
.nMemLen
, aRes
.nSprmId
);
3906 EndSprm( aRes
.nSprmId
); // Switch off Attr
3908 else if( aRes
.nSprmId
< 0x800 ) // Own helper attributes
3912 nSkipChars
= ImportExtSprm(&aRes
);
3914 (aRes
.nSprmId
== eFTN
) || (aRes
.nSprmId
== eEDN
) ||
3915 (aRes
.nSprmId
== eFLD
) || (aRes
.nSprmId
== eAND
)
3918 WW8_CP nMaxLegalSkip
= nTextEnd
- rTextPos
;
3919 // Skip Field/Footnote-/End-Note here
3920 rTextPos
+= std::min
<WW8_CP
>(nSkipChars
, nMaxLegalSkip
);
3921 nSkipPos
= rTextPos
-1;
3925 EndExtSprm( aRes
.nSprmId
);
3929 sal_Int32 nRequestedPos
= m_xSBase
->WW8Cp2Fc(m_xPlcxMan
->GetCpOfs() + rTextPos
, &m_bIsUnicode
);
3930 bool bValidPos
= checkSeek(*m_pStrm
, nRequestedPos
);
3931 SAL_WARN_IF(!bValidPos
, "sw.ww8", "Document claimed to have text at an invalid position, skip attributes for region");
3933 // Find next Attr position (and Skip attributes of field contents if needed)
3934 if (nSkipChars
&& !m_bIgnoreText
)
3935 m_xCtrlStck
->MarkAllAttrsOld();
3936 bool bOldIgnoreText
= m_bIgnoreText
;
3937 m_bIgnoreText
= true;
3938 sal_uInt16 nOldColl
= m_nCurrentColl
;
3939 bool bDoPlcxManPlusPLus
= true;
3943 if( bDoPlcxManPlusPLus
)
3944 m_xPlcxMan
->advance();
3945 nNext
= bValidPos
? m_xPlcxMan
->Where() : nTextEnd
;
3947 if (m_pPostProcessAttrsInfo
&&
3948 m_pPostProcessAttrsInfo
->mnCpStart
== nNext
)
3950 m_pPostProcessAttrsInfo
->mbCopy
= true;
3953 if( (0 <= nNext
) && (nSkipPos
>= nNext
) )
3955 if (nDepthGuard
>= 1024)
3957 SAL_WARN("sw.ww8", "ReadTextAttr hit recursion limit");
3961 nNext
= ReadTextAttr(rTextPos
, nTextEnd
, rbStartLine
, nDepthGuard
+ 1);
3962 bDoPlcxManPlusPLus
= false;
3963 m_bIgnoreText
= true;
3966 if (m_pPostProcessAttrsInfo
&&
3967 nNext
> m_pPostProcessAttrsInfo
->mnCpEnd
)
3969 m_pPostProcessAttrsInfo
->mbCopy
= false;
3972 while( nSkipPos
>= nNext
);
3973 m_bIgnoreText
= bOldIgnoreText
;
3976 m_xCtrlStck
->KillUnlockedAttrs( *m_pPaM
->GetPoint() );
3977 if( nOldColl
!= m_xPlcxMan
->GetColl() )
3978 ProcessCurrentCollChange(aRes
, nullptr, false);
3984 void SwWW8ImplReader::ReadAttrs(WW8_CP
& rTextPos
, WW8_CP
& rNext
, tools::Long nTextEnd
, bool& rbStartLine
)
3986 // Do we have attributes?
3987 if( rTextPos
>= rNext
)
3991 rNext
= ReadTextAttr(rTextPos
, nTextEnd
, rbStartLine
);
3992 if (rTextPos
== rNext
&& rTextPos
>= nTextEnd
)
3995 while( rTextPos
>= rNext
);
3998 else if ( rbStartLine
)
4000 /* No attributes, but still a new line.
4001 * If a line ends with a line break and paragraph attributes or paragraph templates
4002 * do NOT change the line end was not added to the Plcx.Fkp.papx i.e. (nFlags & MAN_MASK_NEW_PAP)
4004 * Due to this we need to set the template here as a kind of special treatment.
4006 if (!m_bCpxStyle
&& m_nCurrentColl
< m_vColl
.size())
4007 SetTextFormatCollAndListLevel(*m_pPaM
, m_vColl
[m_nCurrentColl
]);
4008 rbStartLine
= false;
4013 * CloseAttrEnds to only read the attribute ends at the end of a text or a
4014 * text area (Header, Footnote, ...).
4015 * We ignore attribute starts and fields.
4017 void SwWW8ImplReader::CloseAttrEnds()
4019 // If there are any unclosed sprms then copy them to
4020 // another stack and close the ones that must be closed
4021 std::stack
<sal_uInt16
> aStack
;
4022 m_xPlcxMan
->TransferOpenSprms(aStack
);
4024 while (!aStack
.empty())
4026 sal_uInt16 nSprmId
= aStack
.top();
4027 if ((0 < nSprmId
) && (( eFTN
> nSprmId
) || (0x0800 <= nSprmId
)))
4035 bool SwWW8ImplReader::ReadText(WW8_CP nStartCp
, WW8_CP nTextLen
, ManTypes nType
)
4039 bool bStartLine
= true;
4041 short nDistance
= 0;
4043 m_bWasParaEnd
= false;
4045 m_xCurrentItemSet
.reset();
4048 m_bPgSecBreak
= false;
4050 m_xPlcxMan
= std::make_shared
<WW8PLCFMan
>(m_xSBase
.get(), nType
, nStartCp
);
4051 tools::Long nCpOfs
= m_xPlcxMan
->GetCpOfs(); // Offset for Header/Footer, Footnote
4053 WW8_CP nNext
= m_xPlcxMan
->Where();
4054 m_xPreviousNode
.reset();
4055 sal_uInt8 nDropLines
= 0;
4056 SwCharFormat
* pNewSwCharFormat
= nullptr;
4057 const SwCharFormat
* pFormat
= nullptr;
4059 bool bValidPos
= checkSeek(*m_pStrm
, m_xSBase
->WW8Cp2Fc(nStartCp
+ nCpOfs
, &m_bIsUnicode
));
4063 WW8_CP l
= nStartCp
;
4064 const WW8_CP nMaxPossible
= WW8_CP_MAX
-nStartCp
;
4065 if (nTextLen
> nMaxPossible
)
4067 SAL_WARN_IF(nTextLen
> nMaxPossible
, "sw.ww8", "TextLen too long");
4068 nTextLen
= nMaxPossible
;
4070 WW8_CP nTextEnd
= nStartCp
+nTextLen
;
4071 while (l
< nTextEnd
)
4073 ReadAttrs( l
, nNext
, nTextEnd
, bStartLine
);// Takes SectionBreaks into account, too
4074 OSL_ENSURE(m_pPaM
->GetPointNode().GetTextNode(), "Missing txtnode");
4076 if (m_pPostProcessAttrsInfo
!= nullptr)
4082 bStartLine
= ReadChars(l
, nNext
, nTextEnd
, nCpOfs
);
4084 // If the previous paragraph was a dropcap then do not
4085 // create a new txtnode and join the two paragraphs together
4086 if (bStartLine
&& !m_xPreviousNode
) // Line end
4089 if (m_bCareFirstParaEndInToc
)
4091 m_bCareFirstParaEndInToc
= false;
4092 if (m_pPaM
->End() && m_pPaM
->End()->GetNode().GetTextNode() && m_pPaM
->End()->GetNode().GetTextNode()->Len() == 0)
4095 if (m_bCareLastParaEndInToc
)
4097 m_bCareLastParaEndInToc
= false;
4098 if (m_pPaM
->End() && m_pPaM
->End()->GetNode().GetTextNode() && m_pPaM
->End()->GetNode().GetTextNode()->Len() == 0)
4103 AppendTextNode(*m_pPaM
->GetPoint());
4107 if (SwTextNode
* pPreviousNode
= (bStartLine
&& m_xPreviousNode
) ? m_xPreviousNode
->GetTextNode() : nullptr)
4109 SwTextNode
* pEndNd
= m_pPaM
->GetPointNode().GetTextNode();
4110 SAL_WARN_IF(!pEndNd
, "sw.ww8", "didn't find textnode for dropcap");
4113 const sal_Int32 nDropCapLen
= pPreviousNode
->GetText().getLength();
4115 // Need to reset the font size and text position for the dropcap
4117 SwPaM
aTmp(*pEndNd
, 0, *pEndNd
, nDropCapLen
+1);
4118 m_xCtrlStck
->Delete(aTmp
);
4121 // Get the default document dropcap which we can use as our template
4122 const SwFormatDrop
* defaultDrop
=
4123 static_cast<const SwFormatDrop
*>( GetFormatAttr(RES_PARATR_DROP
));
4124 SwFormatDrop
aDrop(*defaultDrop
);
4126 aDrop
.GetLines() = nDropLines
;
4127 aDrop
.GetDistance() = nDistance
;
4128 aDrop
.GetChars() = writer_cast
<sal_uInt8
>(nDropCapLen
);
4129 // Word has no concept of a "whole word dropcap"
4130 aDrop
.GetWholeWord() = false;
4133 aDrop
.SetCharFormat(const_cast<SwCharFormat
*>(pFormat
));
4134 else if(pNewSwCharFormat
)
4135 aDrop
.SetCharFormat(pNewSwCharFormat
);
4137 SwPosition
aStart(*pEndNd
);
4138 m_xCtrlStck
->NewAttr(aStart
, aDrop
);
4139 m_xCtrlStck
->SetAttr(*m_pPaM
->GetPoint(), RES_PARATR_DROP
);
4141 m_xPreviousNode
.reset();
4143 else if (m_bDropCap
)
4145 // If we have found a dropcap store the textnode
4146 m_xPreviousNode
.reset(new TextNodeListener(m_pPaM
->GetPointNode().GetTextNode()));
4150 aDCS
= m_xPlcxMan
->GetPapPLCF()->HasSprm(46);
4152 aDCS
= m_xPlcxMan
->GetPapPLCF()->HasSprm(0x442C);
4154 if (aDCS
.pSprm
&& aDCS
.nRemainingData
>= 1)
4155 nDropLines
= (*aDCS
.pSprm
) >> 3;
4156 else // There is no Drop Cap Specifier hence no dropcap
4157 m_xPreviousNode
.reset();
4159 SprmResult aDistance
= m_xPlcxMan
->GetPapPLCF()->HasSprm(0x842F);
4160 if (aDistance
.pSprm
&& aDistance
.nRemainingData
>= 2)
4161 nDistance
= SVBT16ToUInt16(aDistance
.pSprm
);
4165 const SwFormatCharFormat
*pSwFormatCharFormat
= nullptr;
4167 if (m_xCurrentItemSet
)
4168 pSwFormatCharFormat
= &(m_xCurrentItemSet
->Get(RES_TXTATR_CHARFMT
));
4170 if (pSwFormatCharFormat
)
4171 pFormat
= pSwFormatCharFormat
->GetCharFormat();
4173 if (m_xCurrentItemSet
&& !pFormat
)
4175 OUString sPrefix
= "WW8Dropcap" + OUString::number(m_nDropCap
++);
4176 pNewSwCharFormat
= m_rDoc
.MakeCharFormat(sPrefix
, m_rDoc
.GetDfltCharFormat());
4177 m_xCurrentItemSet
->ClearItem(RES_CHRATR_ESCAPEMENT
);
4178 pNewSwCharFormat
->SetFormatAttr(*m_xCurrentItemSet
);
4181 m_xCurrentItemSet
.reset();
4185 if (bStartLine
|| m_bWasTabRowEnd
)
4187 // Call all 64 CRs; not for Header and the like
4188 if ((nCrCount
++ & 0x40) == 0 && nType
== MAN_MAINTEXT
&& l
<= nTextLen
)
4190 if (nTextLen
< WW8_CP_MAX
/100)
4191 m_nProgress
= o3tl::narrowing
<sal_uInt16
>(l
* 100 / nTextLen
);
4193 m_nProgress
= o3tl::narrowing
<sal_uInt16
>(l
/ nTextLen
* 100);
4194 m_xProgress
->Update(m_nProgress
); // Update
4198 // If we have encountered a 0x0c which indicates either section of
4199 // pagebreak then look it up to see if it is a section break, and
4200 // if it is not then insert a page break. If it is a section break
4201 // it will be handled as such in the ReadAttrs of the next loop
4204 // We need only to see if a section is ending at this cp,
4205 // the plcf will already be sitting on the correct location
4208 aTemp
.nStartPos
= aTemp
.nEndPos
= WW8_CP_MAX
;
4209 if (m_xPlcxMan
->GetSepPLCF())
4210 m_xPlcxMan
->GetSepPLCF()->GetSprms(&aTemp
);
4211 if ((aTemp
.nStartPos
!= l
) && (aTemp
.nEndPos
!= l
))
4213 // #i39251# - insert text node for page break, if no one inserted.
4214 // #i43118# - refine condition: the anchor
4215 // control stack has to have entries, otherwise it's not needed
4216 // to insert a text node.
4217 if (!bStartLine
&& !m_xAnchorStck
->empty())
4219 AppendTextNode(*m_pPaM
->GetPoint());
4221 m_rDoc
.getIDocumentContentOperations().InsertPoolItem(*m_pPaM
,
4222 SvxFormatBreakItem(SvxBreak::PageBefore
, RES_BREAK
));
4223 m_bFirstParaOfPage
= true;
4224 m_bPgSecBreak
= false;
4229 m_xPreviousNode
.reset();
4231 if (m_pPaM
->GetPoint()->GetContentIndex())
4232 AppendTextNode(*m_pPaM
->GetPoint());
4234 if (!m_bInHyperlink
)
4235 bJoined
= JoinNode(*m_pPaM
);
4243 SwWW8ImplReader::SwWW8ImplReader(sal_uInt8 nVersionPara
, SotStorage
* pStorage
,
4244 SvStream
* pSt
, SwDoc
& rD
, OUString aBaseURL
, bool bNewDoc
, bool bSkipImages
, SwPosition
const &rPos
)
4245 : m_pDocShell(rD
.GetDocShell())
4248 , m_pTableStream(nullptr)
4249 , m_pDataStream(nullptr)
4252 , m_aSectionManager(*this)
4253 , m_aExtraneousParas(rD
)
4254 , m_aInsertedTables(rD
)
4255 , m_aSectionNameGenerator(rD
, "WW")
4256 , m_aGrfNameGenerator(bNewDoc
, OUString('G'))
4257 , m_aParaStyleMapper(rD
)
4258 , m_aCharStyleMapper(rD
)
4259 , m_pFlyFormatOfJustInsertedGraphic(nullptr)
4260 , m_pPreviousNumPaM(nullptr)
4261 , m_pPrevNumRule(nullptr)
4262 , m_pCurrentColl(nullptr)
4263 , m_pDfltTextFormatColl(nullptr)
4264 , m_pStandardFormatColl(nullptr)
4265 , m_pDrawModel(nullptr)
4266 , m_pDrawPg(nullptr)
4267 , m_pNumFieldType(nullptr)
4268 , m_sBaseURL(std::move(aBaseURL
))
4272 , m_bRegardHindiDigits( false )
4273 , m_bDrawCpOValid( false )
4279 , m_eTextCharSet(RTL_TEXTENCODING_ASCII_US
)
4280 , m_eStructCharSet(RTL_TEXTENCODING_ASCII_US
)
4281 , m_eHardCharSet(RTL_TEXTENCODING_DONTKNOW
)
4285 , m_nLFOPosition(USHRT_MAX
)
4292 , m_nWantedVersion(nVersionPara
)
4293 , m_nSwNumLevel(0xff)
4294 , m_nWwNumType(0xff)
4295 , m_pChosenWW8OutlineStyle(nullptr)
4296 , m_nListLevel(MAXLEVEL
)
4297 , m_bNewDoc(bNewDoc
)
4298 , m_bSkipImages(bSkipImages
)
4299 , m_bReadNoTable(false)
4300 , m_bPgSecBreak(false)
4303 , m_bTxbxFlySection(false)
4304 , m_bHasBorder(false)
4306 , m_bIgnoreText(false)
4308 , m_bWasTabRowEnd(false)
4309 , m_bWasTabCellEnd(false)
4311 , m_bHdFtFootnoteEdn(false)
4312 , m_bFootnoteEdn(false)
4313 , m_bIsHeader(false)
4314 , m_bIsFooter(false)
4315 , m_bIsUnicode(false)
4316 , m_bCpxStyle(false)
4317 , m_bStyNormal(false)
4318 , m_bWWBugNormal(false)
4319 , m_bNoAttrImport(false)
4320 , m_bInHyperlink(false)
4321 , m_bWasParaEnd(false)
4326 , m_bEmbeddObj(false)
4327 , m_bCurrentAND_fNumberAcross(false)
4328 , m_bNoLnNumYet(true)
4329 , m_bFirstPara(true)
4330 , m_bFirstParaOfPage(false)
4331 , m_bParaAutoBefore(false)
4332 , m_bParaAutoAfter(false)
4336 , m_bReadTable(false)
4337 , m_bLoadingTOXCache(false)
4338 , m_nEmbeddedTOXLevel(0)
4339 , m_bLoadingTOXHyperlink(false)
4340 , m_bCareFirstParaEndInToc(false)
4341 , m_bCareLastParaEndInToc(false)
4342 , m_bNotifyMacroEventRead(false)
4343 , m_bFuzzing(utl::ConfigManager::IsFuzzing())
4345 m_pStrm
->SetEndian( SvStreamEndian::LITTLE
);
4346 m_aApos
.push_back(false);
4348 mpCursor
= m_rDoc
.CreateUnoCursor(rPos
);
4351 SwWW8ImplReader::~SwWW8ImplReader()
4355 void SwWW8ImplReader::DeleteStack(std::unique_ptr
<SwFltControlStack
> pStck
)
4359 pStck
->SetAttr( *m_pPaM
->GetPoint(), 0, false);
4360 pStck
->SetAttr( *m_pPaM
->GetPoint(), 0, false);
4364 OSL_ENSURE( false, "WW stack already deleted" );
4368 void wwSectionManager::SetSegmentToPageDesc(const wwSection
&rSection
,
4371 SwPageDesc
&rPage
= *rSection
.mpPage
;
4373 SetNumberingType(rSection
, rPage
);
4375 SwFrameFormat
&rFormat
= rPage
.GetMaster();
4377 if(mrReader
.m_xWDop
->fUseBackGroundInAllmodes
) // #i56806# Make sure mrReader is initialized
4378 mrReader
.GraphicCtor();
4380 if (mrReader
.m_xWDop
->fUseBackGroundInAllmodes
&& mrReader
.m_xMSDffManager
)
4382 tools::Rectangle
aRect(0, 0, 100, 100); // A dummy, we don't care about the size
4383 SvxMSDffImportData
aData(aRect
);
4384 rtl::Reference
<SdrObject
> pObject
;
4385 if (mrReader
.m_xMSDffManager
->GetShape(0x401, pObject
, aData
) && !aData
.empty())
4387 // Only handle shape if it is a background shape
4388 if (aData
.begin()->get()->nFlags
& ShapeFlag::Background
)
4390 SfxItemSetFixed
<RES_BACKGROUND
, RES_BACKGROUND
,XATTR_START
, XATTR_END
>
4391 aSet(rFormat
.GetDoc()->GetAttrPool());
4392 mrReader
.MatchSdrItemsIntoFlySet(pObject
.get(), aSet
, mso_lineSimple
,
4393 mso_lineSolid
, mso_sptRectangle
, aRect
);
4394 if ( aSet
.HasItem(RES_BACKGROUND
) )
4395 rFormat
.SetFormatAttr(aSet
.Get(RES_BACKGROUND
));
4397 rFormat
.SetFormatAttr(aSet
);
4401 wwULSpaceData aULData
;
4402 GetPageULData(rSection
, aULData
);
4403 SetPageULSpaceItems(rFormat
, aULData
, rSection
);
4405 rPage
.SetVerticalAdjustment( rSection
.mnVerticalAdjustment
);
4407 SetPage(rPage
, rFormat
, rSection
, bIgnoreCols
);
4409 if (!(rSection
.maSep
.pgbApplyTo
& 1))
4410 SwWW8ImplReader::SetPageBorder(rFormat
, rSection
);
4411 if (!(rSection
.maSep
.pgbApplyTo
& 2))
4412 SwWW8ImplReader::SetPageBorder(rPage
.GetFirstMaster(), rSection
);
4414 mrReader
.SetDocumentGrid(rFormat
, rSection
);
4417 void wwSectionManager::SetUseOn(wwSection
&rSection
)
4419 bool bMirror
= mrReader
.m_xWDop
->fMirrorMargins
||
4420 mrReader
.m_xWDop
->doptypography
.m_f2on1
;
4422 UseOnPage eUseBase
= bMirror
? UseOnPage::Mirror
: UseOnPage::All
;
4423 UseOnPage eUse
= eUseBase
;
4424 if (!mrReader
.m_xWDop
->fFacingPages
)
4425 eUse
|= UseOnPage::HeaderShare
| UseOnPage::FooterShare
;
4426 if (!rSection
.HasTitlePage())
4427 eUse
|= UseOnPage::FirstShare
;
4429 OSL_ENSURE(rSection
.mpPage
, "Makes no sense to call me with no pages to set");
4430 if (rSection
.mpPage
)
4431 rSection
.mpPage
->WriteUseOn(eUse
);
4435 * Set the page descriptor on this node, handle the different cases for a text
4438 static void GiveNodePageDesc(SwNodeIndex
const &rIdx
, const SwFormatPageDesc
&rPgDesc
,
4442 If it's a table here, apply the pagebreak to the table
4443 properties, otherwise we add it to the para at this
4446 if (rIdx
.GetNode().IsTableNode())
4449 rIdx
.GetNode().GetTableNode()->GetTable();
4450 SwFrameFormat
* pApply
= rTable
.GetFrameFormat();
4451 OSL_ENSURE(pApply
, "impossible");
4453 pApply
->SetFormatAttr(rPgDesc
);
4458 rDoc
.getIDocumentContentOperations().InsertPoolItem(aPage
, rPgDesc
);
4463 * Map a word section to a writer page descriptor
4465 SwFormatPageDesc
wwSectionManager::SetSwFormatPageDesc(mySegIter
const &rIter
,
4466 mySegIter
const &rStart
, bool bIgnoreCols
)
4468 if (mrReader
.m_bNewDoc
&& rIter
== rStart
)
4471 mrReader
.m_rDoc
.getIDocumentStylePoolAccess().GetPageDescFromPool(RES_POOLPAGE_STANDARD
);
4475 rIter
->mpPage
= mrReader
.m_rDoc
.MakePageDesc(
4476 SwViewShell::GetShellRes()->GetPageDescName(mnDesc
, ShellResource::NORMAL_PAGE
),
4479 OSL_ENSURE(rIter
->mpPage
, "no page!");
4481 return SwFormatPageDesc();
4483 // Set page before hd/ft
4484 const wwSection
*pPrevious
= nullptr;
4485 if (rIter
!= rStart
)
4486 pPrevious
= &(*(rIter
-1));
4487 SetHdFt(*rIter
, std::distance(rStart
, rIter
), pPrevious
);
4490 // Set hd/ft after set page
4491 SetSegmentToPageDesc(*rIter
, bIgnoreCols
);
4493 SwFormatPageDesc
aRet(rIter
->mpPage
);
4495 rIter
->mpPage
->SetFollow(rIter
->mpPage
);
4497 if (rIter
->PageRestartNo())
4498 aRet
.SetNumOffset(rIter
->PageStartAt());
4504 void wwSectionManager::InsertSegments()
4506 mySegIter aEnd
= maSegments
.end();
4507 mySegIter aStart
= maSegments
.begin();
4508 for (mySegIter aIter
= aStart
; aIter
!= aEnd
; ++aIter
)
4510 // If the section is of type "New column" (0x01), then simply insert a column break.
4511 // But only if there actually are columns on the page, otherwise a column break
4512 // seems to be handled like a page break by MSO.
4513 if ( aIter
->maSep
.bkc
== 1 && aIter
->maSep
.ccolM1
> 0 )
4515 SwPaM
start( aIter
->maStart
);
4516 mrReader
.m_rDoc
.getIDocumentContentOperations().InsertPoolItem( start
, SvxFormatBreakItem(SvxBreak::ColumnBefore
, RES_BREAK
));
4520 mySegIter aNext
= aIter
+1;
4521 mySegIter aPrev
= (aIter
== aStart
) ? aIter
: aIter
-1;
4523 // If two following sections are different in following properties, Word will interpret a continuous
4524 // section break between them as if it was a section break next page.
4525 bool bThisAndPreviousAreCompatible
= ((aIter
->GetPageWidth() == aPrev
->GetPageWidth()) &&
4526 (aIter
->GetPageHeight() == aPrev
->GetPageHeight()) && (aIter
->IsLandScape() == aPrev
->IsLandScape()));
4528 bool bInsertSection
= (aIter
!= aStart
) && aIter
->IsContinuous() && bThisAndPreviousAreCompatible
;
4529 bool bInsertPageDesc
= !bInsertSection
;
4530 // HACK Force new pagedesc if left/right margins change, otherwise e.g. floating tables may be anchored improperly.
4531 if( aIter
->maSep
.dxaLeft
!= aPrev
->maSep
.dxaLeft
|| aIter
->maSep
.dxaRight
!= aPrev
->maSep
.dxaRight
)
4532 bInsertPageDesc
= true;
4533 bool bProtected
= SectionIsProtected(*aIter
); // do we really need this ?? I guess I have a different logic in editshell which disables this...
4535 if (bInsertPageDesc
)
4538 If a cont section follows this section then we won't be
4539 creating a page desc with 2+ cols as we cannot host a one
4540 col section in a 2+ col pagedesc and make it look like
4541 word. But if the current section actually has columns then
4542 we are forced to insert a section here as well as a page
4546 bool bIgnoreCols
= bInsertSection
;
4547 bool bThisAndNextAreCompatible
= (aNext
== aEnd
) ||
4548 ((aIter
->GetPageWidth() == aNext
->GetPageWidth()) &&
4549 (aIter
->GetPageHeight() == aNext
->GetPageHeight()) &&
4550 (aIter
->IsLandScape() == aNext
->IsLandScape()));
4552 if ((aNext
!= aEnd
&& aNext
->IsContinuous() && bThisAndNextAreCompatible
) || bProtected
)
4555 if ((aIter
->NoCols() > 1) || bProtected
)
4556 bInsertSection
= true;
4559 SwFormatPageDesc
aDesc(SetSwFormatPageDesc(aIter
, aStart
, bIgnoreCols
));
4560 if (!aDesc
.GetPageDesc())
4563 // special case handling for odd/even section break
4564 // a) as before create a new page style for the section break
4565 // b) set Layout of generated page style to right/left ( according
4566 // to section break odd/even )
4567 // c) create a new style to follow the break page style
4568 if ( aIter
->maSep
.bkc
== 3 || aIter
->maSep
.bkc
== 4 )
4570 // SetSwFormatPageDesc calls some methods that could
4571 // modify aIter (e.g. wwSection ).
4572 // Since we call SetSwFormatPageDesc below to generate the
4573 // 'Following' style of the Break style, it is safer
4574 // to take a copy of the contents of aIter.
4575 wwSection aTmpSection
= *aIter
;
4576 // create a new following page style
4577 SwFormatPageDesc
aFollow(SetSwFormatPageDesc(aIter
, aStart
, bIgnoreCols
));
4578 // restore any contents of aIter trashed by SetSwFormatPageDesc
4579 *aIter
= aTmpSection
;
4581 // Handle the section break
4582 UseOnPage eUseOnPage
= UseOnPage::Left
;
4583 if ( aIter
->maSep
.bkc
== 4 ) // Odd ( right ) Section break
4584 eUseOnPage
= UseOnPage::Right
;
4586 // Keep the share flags.
4587 aDesc
.GetPageDesc()->SetUseOn( eUseOnPage
);
4588 aDesc
.GetPageDesc()->SetFollow( aFollow
.GetPageDesc() );
4591 // Avoid setting the page style at the very beginning since it is always the default style anyway,
4592 // unless it is needed to specify a page number.
4593 if (aIter
!= aStart
|| aDesc
.GetNumOffset())
4594 GiveNodePageDesc(aIter
->maStart
, aDesc
, mrReader
.m_rDoc
);
4597 SwTextNode
* pTextNd
= nullptr;
4600 // Start getting the bounds of this section
4601 SwPaM
aSectPaM(*mrReader
.m_pPaM
, mrReader
.m_pPaM
);
4602 SwNodeIndex
aAnchor(aSectPaM
.GetPoint()->GetNode());
4605 aAnchor
= aNext
->maStart
;
4606 aSectPaM
.GetPoint()->Assign(aAnchor
);
4607 aSectPaM
.Move(fnMoveBackward
);
4610 const SwPosition
* pPos
= aSectPaM
.GetPoint();
4611 SwTextNode
const*const pSttNd
= pPos
->GetNode().GetTextNode();
4612 const SwTableNode
* pTableNd
= pSttNd
? pSttNd
->FindTableNode() : nullptr;
4616 mrReader
.m_rDoc
.GetNodes().MakeTextNode(aAnchor
.GetNode(),
4617 mrReader
.m_rDoc
.getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_TEXT
));
4619 aSectPaM
.GetPoint()->Assign(*pTextNd
, 0);
4624 aSectPaM
.GetPoint()->Assign(aIter
->maStart
);
4626 bool bHasOwnHdFt
= false;
4628 In this nightmare scenario the continuous section has its own
4629 headers and footers so we will try and find a hard page break
4630 between here and the end of the section and put the headers and
4633 if (!bInsertPageDesc
)
4636 mrReader
.HasOwnHeaderFooter(
4637 aIter
->maSep
.grpfIhdt
& ~(WW8_HEADER_FIRST
| WW8_FOOTER_FIRST
),
4638 aIter
->maSep
.grpfIhdt
, std::distance(aStart
, aIter
)
4643 // #i40766# Need to cache the page descriptor in case there is
4644 // no page break in the section
4645 SwPageDesc
*pOrig
= aIter
->mpPage
;
4646 bool bFailed
= true;
4647 SwFormatPageDesc
aDesc(SetSwFormatPageDesc(aIter
, aStart
, true));
4648 if (aDesc
.GetPageDesc())
4650 SwNodeOffset nStart
= aSectPaM
.Start()->GetNodeIndex();
4651 SwNodeOffset nEnd
= aSectPaM
.End()->GetNodeIndex();
4652 for(; nStart
<= nEnd
; ++nStart
)
4654 SwNode
* pNode
= mrReader
.m_rDoc
.GetNodes()[nStart
];
4657 if (sw::util::HasPageBreak(*pNode
))
4659 SwNodeIndex
aIdx(*pNode
);
4660 GiveNodePageDesc(aIdx
, aDesc
, mrReader
.m_rDoc
);
4668 aIter
->mpPage
= pOrig
;
4672 // End getting the bounds of this section, quite a job eh?
4673 SwSectionFormat
*pRet
= InsertSection(aSectPaM
, *aIter
);
4674 // The last section if continuous is always unbalanced
4677 // Set the columns to be UnBalanced if that compatibility option is set
4678 if (mrReader
.m_xWDop
->fNoColumnBalance
)
4679 pRet
->SetFormatAttr(SwFormatNoBalancedColumns(true));
4682 // Otherwise set to unbalanced if the following section is
4683 // not continuous, (which also means that the last section
4685 if (aNext
== aEnd
|| !aNext
->IsContinuous())
4686 pRet
->SetFormatAttr(SwFormatNoBalancedColumns(true));
4693 SwPaM
aTest(*pTextNd
);
4694 mrReader
.m_rDoc
.getIDocumentContentOperations().DelFullPara(aTest
);
4700 void wwExtraneousParas::delete_all_from_doc()
4702 auto aEnd
= m_aTextNodes
.rend();
4703 for (auto aI
= m_aTextNodes
.rbegin(); aI
!= aEnd
; ++aI
)
4705 ExtraTextNodeListener
& rListener
= const_cast<ExtraTextNodeListener
&>(*aI
);
4706 SwTextNode
* pTextNode
= rListener
.GetTextNode();
4707 rListener
.StopListening(pTextNode
);
4709 SwPaM
aTest(*pTextNode
);
4710 m_rDoc
.getIDocumentContentOperations().DelFullPara(aTest
);
4712 m_aTextNodes
.clear();
4715 void wwExtraneousParas::insert(SwTextNode
*pTextNode
)
4717 m_aTextNodes
.emplace(pTextNode
, this);
4720 void wwExtraneousParas::remove_if_present(SwModify
* pModify
)
4722 auto it
= std::find_if(m_aTextNodes
.begin(), m_aTextNodes
.end(),
4723 [pModify
](const ExtraTextNodeListener
& rEntry
) { return rEntry
.GetTextNode() == pModify
; });
4724 if (it
== m_aTextNodes
.end())
4726 SAL_WARN("sw.ww8", "It is unexpected to drop a para scheduled for removal");
4727 m_aTextNodes
.erase(it
);
4730 TextNodeListener::TextNodeListener(SwTextNode
* pTextNode
)
4731 : m_pTextNode(pTextNode
)
4733 m_pTextNode
->Add(this);
4736 TextNodeListener::~TextNodeListener()
4740 StopListening(m_pTextNode
);
4743 void TextNodeListener::SwClientNotify(const SwModify
& rModify
, const SfxHint
& rHint
)
4745 if (rHint
.GetId() != SfxHintId::SwLegacyModify
)
4747 auto pLegacy
= static_cast<const sw::LegacyModifyHint
*>(&rHint
);
4748 //Â ofz#41398 drop a para scheduled for deletion if something else deletes it
4749 // before wwExtraneousParas gets its chance to do so. Not the usual scenario,
4750 // indicates an underlying bug.
4751 if (pLegacy
->GetWhich() == RES_OBJECTDYING
)
4752 removed(const_cast<SwModify
*>(&rModify
));
4755 void TextNodeListener::StopListening(SwModify
* pTextNode
)
4757 pTextNode
->Remove(this);
4758 m_pTextNode
= nullptr;
4761 void TextNodeListener::removed(SwModify
* pTextNode
)
4763 StopListening(pTextNode
);
4766 void wwExtraneousParas::ExtraTextNodeListener::removed(SwModify
* pTextNode
)
4768 m_pOwner
->remove_if_present(pTextNode
);
4771 void SwWW8ImplReader::StoreMacroCmds()
4773 if (!m_xWwFib
->m_lcbCmds
)
4776 bool bValidPos
= checkSeek(*m_pTableStream
, m_xWwFib
->m_fcCmds
);
4780 uno::Reference
< embed::XStorage
> xRoot(m_pDocShell
->GetStorage());
4787 uno::Reference
< io::XStream
> xStream
=
4788 xRoot
->openStreamElement( SL::aMSMacroCmds
, embed::ElementModes::READWRITE
);
4789 std::unique_ptr
<SvStream
> xOutStream(::utl::UcbStreamHelper::CreateStream(xStream
));
4791 sal_uInt32 lcbCmds
= std::min
<sal_uInt32
>(m_xWwFib
->m_lcbCmds
, m_pTableStream
->remainingSize());
4792 std::unique_ptr
<sal_uInt8
[]> xBuffer(new sal_uInt8
[lcbCmds
]);
4793 m_xWwFib
->m_lcbCmds
= m_pTableStream
->ReadBytes(xBuffer
.get(), lcbCmds
);
4794 xOutStream
->WriteBytes(xBuffer
.get(), m_xWwFib
->m_lcbCmds
);
4801 void SwWW8ImplReader::ReadDocVars()
4803 std::vector
<OUString
> aDocVarStrings
;
4804 std::vector
<ww::bytes
> aDocVarStringIds
;
4805 std::vector
<OUString
> aDocValueStrings
;
4806 WW8ReadSTTBF(!m_bVer67
, *m_pTableStream
, m_xWwFib
->m_fcStwUser
,
4807 m_xWwFib
->m_lcbStwUser
, m_bVer67
? 2 : 0, m_eStructCharSet
,
4808 aDocVarStrings
, &aDocVarStringIds
, &aDocValueStrings
);
4809 if (m_bVer67
) return;
4811 uno::Reference
<document::XDocumentPropertiesSupplier
> xDPS(
4812 m_pDocShell
->GetModel(), uno::UNO_QUERY_THROW
);
4813 uno::Reference
<document::XDocumentProperties
> xDocProps(
4814 xDPS
->getDocumentProperties());
4815 OSL_ENSURE(xDocProps
.is(), "DocumentProperties is null");
4816 uno::Reference
<beans::XPropertyContainer
> xUserDefinedProps
=
4817 xDocProps
->getUserDefinedProperties();
4818 OSL_ENSURE(xUserDefinedProps
.is(), "UserDefinedProperties is null");
4820 for(size_t i
=0; i
<aDocVarStrings
.size(); i
++)
4822 const OUString
&rName
= aDocVarStrings
[i
];
4826 xUserDefinedProps
->addProperty( rName
,
4827 beans::PropertyAttribute::REMOVABLE
,
4829 } catch (const uno::Exception
&) {
4838 void SwWW8ImplReader::ReadDocInfo()
4843 uno::Reference
<document::XDocumentPropertiesSupplier
> xDPS(
4844 m_pDocShell
->GetModel(), uno::UNO_QUERY_THROW
);
4845 uno::Reference
<document::XDocumentProperties
> xDocProps(
4846 xDPS
->getDocumentProperties());
4847 OSL_ENSURE(xDocProps
.is(), "DocumentProperties is null");
4849 if (!xDocProps
.is())
4852 if ( m_xWwFib
->m_fDot
)
4854 SfxMedium
* pMedium
= m_pDocShell
->GetMedium();
4857 const OUString
& aName
= pMedium
->GetName();
4858 INetURLObject
aURL( aName
);
4859 OUString sTemplateURL
= aURL
.GetMainURL(INetURLObject::DecodeMechanism::ToIUri
);
4860 if ( !sTemplateURL
.isEmpty() )
4861 xDocProps
->setTemplateURL( sTemplateURL
);
4864 else if (m_xWwFib
->m_lcbSttbfAssoc
) // not a template, and has a SttbfAssoc
4866 auto nCur
= m_pTableStream
->Tell();
4868 // point at tgc record
4869 if (!checkSeek(*m_pTableStream
, m_xWwFib
->m_fcSttbfAssoc
) || !aSttb
.Read(*m_pTableStream
))
4870 SAL_WARN("sw.ww8", "** Read of SttbAssoc data failed!!!! ");
4871 m_pTableStream
->Seek( nCur
); // return to previous position, is that necessary?
4872 OUString sPath
= aSttb
.getStringAtIndex( 0x1 );
4874 // attempt to convert to url (won't work for obvious reasons on linux)
4875 if ( !sPath
.isEmpty() )
4876 osl::FileBase::getFileURLFromSystemPath( sPath
, aURL
);
4878 xDocProps
->setTemplateURL( aURL
);
4880 xDocProps
->setTemplateURL( sPath
);
4883 sfx2::LoadOlePropertySet(xDocProps
, m_pStg
);
4886 static void lcl_createTemplateToProjectEntry( const uno::Reference
< container::XNameContainer
>& xPrjNameCache
, const OUString
& sTemplatePathOrURL
, const OUString
& sVBAProjName
)
4888 if ( !xPrjNameCache
.is() )
4892 aObj
.SetURL( sTemplatePathOrURL
);
4893 bool bIsURL
= aObj
.GetProtocol() != INetProtocol::NotValid
;
4896 aURL
= sTemplatePathOrURL
;
4899 osl::FileBase::getFileURLFromSystemPath( sTemplatePathOrURL
, aURL
);
4900 aObj
.SetURL( aURL
);
4904 OUString templateNameWithExt
= aObj
.GetLastName();
4905 sal_Int32 nIndex
= templateNameWithExt
.lastIndexOf( '.' );
4908 OUString templateName
= templateNameWithExt
.copy( 0, nIndex
);
4909 xPrjNameCache
->insertByName( templateName
, uno::Any( sVBAProjName
) );
4912 catch( const uno::Exception
& )
4919 class WW8Customizations
4921 SvStream
* mpTableStream
;
4924 WW8Customizations( SvStream
*, WW8Fib
const & );
4925 void Import( SwDocShell
* pShell
);
4930 WW8Customizations::WW8Customizations( SvStream
* pTableStream
, WW8Fib
const & rFib
) : mpTableStream(pTableStream
), mWw8Fib( rFib
)
4934 void WW8Customizations::Import( SwDocShell
* pShell
)
4936 if ( mWw8Fib
.m_lcbCmds
== 0 || !IsEightPlus(mWw8Fib
.GetFIBVersion()) )
4941 sal_uInt64 nCur
= mpTableStream
->Tell();
4942 if (!checkSeek(*mpTableStream
, mWw8Fib
.m_fcCmds
)) // point at tgc record
4944 SAL_WARN("sw.ww8", "** Seek to Customization data failed!!!! ");
4947 bool bReadResult
= aTCG
.Read( *mpTableStream
);
4948 mpTableStream
->Seek( nCur
); // return to previous position, is that necessary?
4951 SAL_WARN("sw.ww8", "** Read of Customization data failed!!!! ");
4954 aTCG
.ImportCustomToolBar( *pShell
);
4958 SAL_WARN("sw.ww8", "** Read of Customization data failed!!!! epically");
4962 void SwWW8ImplReader::ReadGlobalTemplateSettings( std::u16string_view sCreatedFrom
, const uno::Reference
< container::XNameContainer
>& xPrjNameCache
)
4967 SvtPathOptions aPathOpt
;
4968 const OUString
& aAddinPath
= aPathOpt
.GetAddinPath();
4969 uno::Sequence
< OUString
> sGlobalTemplates
;
4971 // first get the autoload addins in the directory STARTUP
4972 uno::Reference
<ucb::XSimpleFileAccess3
> xSFA(ucb::SimpleFileAccess::create(::comphelper::getProcessComponentContext()));
4974 if( xSFA
->isFolder( aAddinPath
) )
4975 sGlobalTemplates
= xSFA
->getFolderContents( aAddinPath
, false );
4977 for ( const auto& rGlobalTemplate
: std::as_const(sGlobalTemplates
) )
4980 aObj
.SetURL( rGlobalTemplate
);
4981 bool bIsURL
= aObj
.GetProtocol() != INetProtocol::NotValid
;
4984 aURL
= rGlobalTemplate
;
4986 osl::FileBase::getFileURLFromSystemPath( rGlobalTemplate
, aURL
);
4987 if ( !aURL
.endsWithIgnoreAsciiCase( ".dot" ) || ( !sCreatedFrom
.empty() && sCreatedFrom
== aURL
) )
4988 continue; // don't try and read the same document as ourselves
4990 tools::SvRef
<SotStorage
> rRoot
= new SotStorage( aURL
, StreamMode::STD_READWRITE
);
4992 BasicProjImportHelper
aBasicImporter( *m_pDocShell
);
4993 // Import vba via oox filter
4994 aBasicImporter
.import( m_pDocShell
->GetMedium()->GetInputStream() );
4995 lcl_createTemplateToProjectEntry( xPrjNameCache
, aURL
, aBasicImporter
.getProjectName() );
4996 // Read toolbars & menus
4997 tools::SvRef
<SotStorageStream
> refMainStream
= rRoot
->OpenSotStream( "WordDocument");
4998 refMainStream
->SetEndian(SvStreamEndian::LITTLE
);
4999 WW8Fib
aWwFib( *refMainStream
, 8 );
5000 tools::SvRef
<SotStorageStream
> xTableStream
=
5001 rRoot
->OpenSotStream(aWwFib
.m_fWhichTableStm
? OUString(SL::a1Table
) : OUString(SL::a0Table
), StreamMode::STD_READ
);
5003 if (xTableStream
.is() && ERRCODE_NONE
== xTableStream
->GetError())
5005 xTableStream
->SetEndian(SvStreamEndian::LITTLE
);
5006 WW8Customizations
aGblCustomisations( xTableStream
.get(), aWwFib
);
5007 aGblCustomisations
.Import( m_pDocShell
);
5012 ErrCode
SwWW8ImplReader::CoreLoad(WW8Glossary
const *pGloss
)
5014 m_rDoc
.SetDocumentType( SwDoc::DOCTYPE_MSWORD
);
5015 if (m_bNewDoc
&& m_pStg
&& !pGloss
)
5017 // Initialize RDF metadata, to be able to add statements during the import.
5020 uno::Reference
<frame::XModel
> const xModel(m_rDoc
.GetDocShell()->GetBaseModel());
5021 uno::Reference
<rdf::XDocumentMetadataAccess
> xDocumentMetadataAccess(xModel
, uno::UNO_QUERY_THROW
);
5022 uno::Reference
<uno::XComponentContext
> xComponentContext(comphelper::getProcessComponentContext());
5023 uno::Reference
<embed::XStorage
> xStorage
= comphelper::OStorageHelper::GetTemporaryStorage();
5024 const uno::Reference
<rdf::XURI
> xBaseURI(sfx2::createBaseURI(xComponentContext
, xModel
, m_sBaseURL
));
5025 uno::Reference
<task::XInteractionHandler
> xHandler
;
5026 xDocumentMetadataAccess
->loadMetadataFromStorage(xStorage
, xBaseURI
, xHandler
);
5028 catch (const uno::Exception
&)
5030 TOOLS_WARN_EXCEPTION("sw.ww8", "failed to initialize RDF metadata");
5035 auto pFibData
= std::make_shared
<::ww8::WW8FibData
>();
5037 if (m_xWwFib
->m_fReadOnlyRecommended
)
5038 pFibData
->setReadOnlyRecommended(true);
5040 pFibData
->setReadOnlyRecommended(false);
5042 if (m_xWwFib
->m_fWriteReservation
)
5043 pFibData
->setWriteReservation(true);
5045 pFibData
->setWriteReservation(false);
5047 m_rDoc
.getIDocumentExternalData().setExternalData(::sw::tExternalDataType::FIB
, pFibData
);
5049 ::sw::tExternalDataPointer pSttbfAsoc
5050 = std::make_shared
<::ww8::WW8Sttb
<ww8::WW8Struct
>>(*m_pTableStream
, m_xWwFib
->m_fcSttbfAssoc
, m_xWwFib
->m_lcbSttbfAssoc
);
5052 m_rDoc
.getIDocumentExternalData().setExternalData(::sw::tExternalDataType::STTBF_ASSOC
, pSttbfAsoc
);
5054 if (m_xWwFib
->m_fWriteReservation
|| m_xWwFib
->m_fReadOnlyRecommended
)
5056 SwDocShell
* pDocShell
= m_rDoc
.GetDocShell();
5058 pDocShell
->SetReadOnlyUI();
5061 m_pPaM
= mpCursor
.get();
5063 m_xCtrlStck
.reset(new SwWW8FltControlStack(m_rDoc
, m_nFieldFlags
, *this));
5065 m_xRedlineStack
.reset(new sw::util::RedlineStack(m_rDoc
));
5068 RefFieldStck: Keeps track of bookmarks which may be inserted as
5071 m_xReffedStck
.reset(new SwWW8ReferencedFltEndStack(m_rDoc
, m_nFieldFlags
));
5072 m_xReffingStck
.reset(new SwWW8FltRefStack(m_rDoc
, m_nFieldFlags
));
5074 m_xAnchorStck
.reset(new SwWW8FltAnchorStack(m_rDoc
, m_nFieldFlags
));
5076 size_t nPageDescOffset
= m_rDoc
.GetPageDescCnt();
5078 RedlineFlags eMode
= RedlineFlags::ShowInsert
| RedlineFlags::ShowDelete
;
5080 m_oSprmParser
.emplace(*m_xWwFib
);
5082 // Set handy helper variables
5083 m_bVer6
= (6 == m_xWwFib
->m_nVersion
);
5084 m_bVer7
= (7 == m_xWwFib
->m_nVersion
);
5085 m_bVer67
= m_bVer6
|| m_bVer7
;
5086 m_bVer8
= (8 == m_xWwFib
->m_nVersion
);
5088 m_eTextCharSet
= WW8Fib::GetFIBCharset(m_xWwFib
->m_chse
, m_xWwFib
->m_lid
);
5089 m_eStructCharSet
= WW8Fib::GetFIBCharset(m_xWwFib
->m_chseTables
, m_xWwFib
->m_lid
);
5091 m_bWWBugNormal
= m_xWwFib
->m_nProduct
== 0xc03d;
5093 m_xProgress
.reset(new ImportProgress(m_pDocShell
, 0, 100));
5096 m_xFonts
.reset(new WW8Fonts(*m_pTableStream
, *m_xWwFib
));
5098 // Document Properties
5099 m_xWDop
.reset(new WW8Dop(*m_pTableStream
, m_xWwFib
->m_nFib
, m_xWwFib
->m_fcDop
,
5100 m_xWwFib
->m_lcbDop
));
5106 Import revisioning data: author names
5108 if( m_xWwFib
->m_lcbSttbfRMark
)
5110 ReadRevMarkAuthorStrTabl(*m_pTableStream
,
5111 m_xWwFib
->m_fcSttbfRMark
,
5112 m_xWwFib
->m_lcbSttbfRMark
, m_rDoc
);
5115 // Initialize our String/ID map for Linked Sections
5116 std::vector
<OUString
> aLinkStrings
;
5117 std::vector
<ww::bytes
> aStringIds
;
5119 WW8ReadSTTBF(!m_bVer67
, *m_pTableStream
, m_xWwFib
->m_fcSttbFnm
,
5120 m_xWwFib
->m_lcbSttbFnm
, m_bVer67
? 2 : 0, m_eStructCharSet
,
5121 aLinkStrings
, &aStringIds
);
5123 for (size_t i
=0; i
< aLinkStrings
.size() && i
< aStringIds
.size(); ++i
)
5125 const ww::bytes
& stringId
= aStringIds
[i
];
5126 if (stringId
.size() < sizeof(WW8_STRINGID
))
5128 SAL_WARN("sw.ww8", "SwWW8ImplReader::CoreLoad: WW8_STRINGID is too short");
5131 const WW8_STRINGID
*stringIdStruct
= reinterpret_cast<const WW8_STRINGID
*>(stringId
.data());
5132 m_aLinkStringMap
[SVBT16ToUInt16(stringIdStruct
->nStringId
)] = aLinkStrings
[i
];
5135 ReadDocVars(); // import document variables as meta information.
5137 m_xProgress
->Update(m_nProgress
); // Update
5139 m_xLstManager
.reset(new WW8ListManager(*m_pTableStream
, *this));
5142 first (1) import all styles (see WW8PAR2.CXX)
5143 BEFORE the import of the lists !!
5145 m_xProgress
->Update(m_nProgress
); // Update
5146 m_xStyles
.reset(new WW8RStyle(*m_xWwFib
, this)); // Styles
5147 m_xStyles
->Import();
5150 In the end: (also see WW8PAR3.CXX)
5152 Go through all Styles and attach respective List Format
5153 AFTER we imported the Styles and AFTER we imported the Lists!
5155 m_xProgress
->Update(m_nProgress
); // Update
5156 m_xStyles
->PostProcessStyles();
5158 if (!m_vColl
.empty())
5161 m_xSBase
.reset(new WW8ScannerBase(m_pStrm
,m_pTableStream
,m_pDataStream
, m_xWwFib
.get()));
5163 if (m_xSBase
->AreThereFootnotes())
5165 static const SwFootnoteNum eNumA
[4] =
5167 FTNNUM_DOC
, FTNNUM_CHAPTER
, FTNNUM_PAGE
, FTNNUM_DOC
5170 SwFootnoteInfo aInfo
= m_rDoc
.GetFootnoteInfo(); // Copy-Ctor private
5172 aInfo
.m_ePos
= FTNPOS_PAGE
;
5173 aInfo
.m_eNum
= eNumA
[m_xWDop
->rncFootnote
];
5174 sal_uInt16 nfcFootnoteRef
= m_xWDop
->nfcFootnoteRef
;
5175 aInfo
.m_aFormat
.SetNumberingType(WW8ListManager::GetSvxNumTypeFromMSONFC(nfcFootnoteRef
));
5176 if( m_xWDop
->nFootnote
)
5177 aInfo
.m_nFootnoteOffset
= m_xWDop
->nFootnote
- 1;
5178 m_rDoc
.SetFootnoteInfo( aInfo
);
5180 if (m_xSBase
->AreThereEndnotes())
5182 SwEndNoteInfo aInfo
= m_rDoc
.GetEndNoteInfo(); // Same as for Footnote
5183 sal_uInt16 nfcEdnRef
= m_xWDop
->nfcEdnRef
;
5184 aInfo
.m_aFormat
.SetNumberingType(WW8ListManager::GetSvxNumTypeFromMSONFC(nfcEdnRef
));
5186 aInfo
.m_nFootnoteOffset
= m_xWDop
->nEdn
- 1;
5187 m_rDoc
.SetEndNoteInfo( aInfo
);
5189 if (m_xSBase
->GetEndnoteCount() > 2)
5191 // This compatibility flag only works in easy cases, disable it for anything non-trivial
5193 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::CONTINUOUS_ENDNOTES
, false);
5197 if (m_xWwFib
->m_lcbPlcfhdd
)
5198 m_xHdFt
.reset(new WW8PLCF_HdFt(m_pTableStream
, *m_xWwFib
, *m_xWDop
));
5202 // inserting into an existing document:
5203 // As only complete paragraphs are inserted, the current one
5204 // needs to be split - once or even twice.
5205 const SwPosition
* pPos
= m_pPaM
->GetPoint();
5207 // split current paragraph to get new paragraph for the insertion
5208 m_rDoc
.getIDocumentContentOperations().SplitNode( *pPos
, false );
5210 // another split, if insertion position was not at the end of the current paragraph.
5211 SwTextNode
const*const pTextNd
= pPos
->GetNode().GetTextNode();
5212 if ( pTextNd
->GetText().getLength() )
5214 m_rDoc
.getIDocumentContentOperations().SplitNode( *pPos
, false );
5215 // move PaM back to the newly empty paragraph
5216 m_pPaM
->Move( fnMoveBackward
);
5219 // suppress insertion of tables inside footnotes.
5220 const SwNodeOffset nNd
= pPos
->GetNodeIndex();
5221 m_bReadNoTable
= ( nNd
< m_rDoc
.GetNodes().GetEndOfInserts().GetIndex() &&
5222 m_rDoc
.GetNodes().GetEndOfInserts().StartOfSectionIndex() < nNd
);
5225 m_xProgress
->Update(m_nProgress
); // Update
5227 // loop for each glossary entry and add dummy section node
5230 WW8PLCF
aPlc(*m_pTableStream
, m_xWwFib
->m_fcPlcfglsy
, m_xWwFib
->m_lcbPlcfglsy
, 0);
5232 WW8_CP nStart
, nEnd
;
5235 for (int i
= 0; i
< pGloss
->GetNoStrings(); ++i
, aPlc
.advance())
5237 SwNodeIndex
aIdx( m_rDoc
.GetNodes().GetEndOfContent());
5238 SwTextFormatColl
* pColl
=
5239 m_rDoc
.getIDocumentStylePoolAccess().GetTextCollFromPool(RES_POOLCOLL_STANDARD
,
5241 SwStartNode
*pNode
=
5242 m_rDoc
.GetNodes().MakeTextSection(aIdx
.GetNode(),
5243 SwNormalStartNode
,pColl
);
5244 m_pPaM
->GetPoint()->Assign( pNode
->GetIndex()+1 );
5245 aPlc
.Get( nStart
, nEnd
, pDummy
);
5246 ReadText(nStart
,nEnd
-nStart
-1,MAN_MAINTEXT
);
5249 else // ordinary case
5251 if (m_bNewDoc
&& m_pStg
) /*meaningless for a glossary */
5253 m_pDocShell
->SetIsTemplate( m_xWwFib
->m_fDot
); // point at tgc record
5254 uno::Reference
<document::XDocumentPropertiesSupplier
> const
5255 xDocPropSupp(m_pDocShell
->GetModel(), uno::UNO_QUERY_THROW
);
5256 uno::Reference
< document::XDocumentProperties
> xDocProps( xDocPropSupp
->getDocumentProperties(), uno::UNO_SET_THROW
);
5258 OUString sCreatedFrom
= xDocProps
->getTemplateURL();
5259 uno::Reference
< container::XNameContainer
> xPrjNameCache
;
5260 uno::Reference
< lang::XMultiServiceFactory
> xSF(m_pDocShell
->GetModel(), uno::UNO_QUERY
);
5262 xPrjNameCache
.set( xSF
->createInstance( "ooo.vba.VBAProjectNameProvider" ), uno::UNO_QUERY
);
5264 // Read Global templates
5265 ReadGlobalTemplateSettings( sCreatedFrom
, xPrjNameCache
);
5267 // Create and insert Word vba Globals
5269 uno::Sequence
< uno::Any
> aArgs
{ uno::Any(m_pDocShell
->GetModel()) };
5272 aGlobs
<<= ::comphelper::getProcessServiceFactory()->createInstanceWithArguments( "ooo.vba.word.Globals", aArgs
);
5274 catch (const uno::Exception
&)
5276 SAL_WARN("sw.ww8", "SwWW8ImplReader::CoreLoad: ooo.vba.word.Globals is not available");
5279 #if HAVE_FEATURE_SCRIPTING
5282 BasicManager
*pBasicMan
= m_pDocShell
->GetBasicManager();
5284 pBasicMan
->SetGlobalUNOConstant( "VBAGlobals", aGlobs
);
5287 BasicProjImportHelper
aBasicImporter( *m_pDocShell
);
5288 // Import vba via oox filter
5289 bool bRet
= aBasicImporter
.import( m_pDocShell
->GetMedium()->GetInputStream() );
5291 lcl_createTemplateToProjectEntry( xPrjNameCache
, sCreatedFrom
, aBasicImporter
.getProjectName() );
5292 WW8Customizations
aCustomisations( m_pTableStream
, *m_xWwFib
);
5293 aCustomisations
.Import( m_pDocShell
);
5296 m_rDoc
.SetContainsMSVBasic(true);
5300 ReadText(0, m_xWwFib
->m_ccpText
, MAN_MAINTEXT
);
5303 m_xProgress
->Update(m_nProgress
); // Update
5305 if (m_pDrawPg
&& m_xMSDffManager
&& m_xMSDffManager
->GetShapeOrders())
5307 // Helper array to chain the inserted frames (instead of SdrTextObj)
5308 SvxMSDffShapeTxBxSort aTxBxSort
;
5310 // Ensure correct z-order of read Escher objects
5311 sal_uInt16 nShapeCount
= m_xMSDffManager
->GetShapeOrders()->size();
5313 for (sal_uInt16 nShapeNum
=0; nShapeNum
< nShapeCount
; nShapeNum
++)
5315 SvxMSDffShapeOrder
*pOrder
=
5316 (*m_xMSDffManager
->GetShapeOrders())[nShapeNum
].get();
5317 // Insert Pointer into new Sort array
5318 if (pOrder
->nTxBxComp
&& pOrder
->pFly
)
5319 aTxBxSort
.insert(pOrder
);
5322 if( !aTxBxSort
.empty() )
5324 SwFormatChain aChain
;
5325 for( SvxMSDffShapeTxBxSort::iterator it
= aTxBxSort
.begin(); it
!= aTxBxSort
.end(); ++it
)
5327 SvxMSDffShapeOrder
*pOrder
= *it
;
5329 // Initialize FlyFrame Formats
5330 SwFlyFrameFormat
* pFlyFormat
= pOrder
->pFly
;
5331 SwFlyFrameFormat
* pNextFlyFormat
= nullptr;
5332 SwFlyFrameFormat
* pPrevFlyFormat
= nullptr;
5334 // Determine successor, if we can
5335 SvxMSDffShapeTxBxSort::iterator tmpIter1
= it
;
5337 if( tmpIter1
!= aTxBxSort
.end() )
5339 SvxMSDffShapeOrder
*pNextOrder
= *tmpIter1
;
5340 if ((0xFFFF0000 & pOrder
->nTxBxComp
)
5341 == (0xFFFF0000 & pNextOrder
->nTxBxComp
))
5342 pNextFlyFormat
= pNextOrder
->pFly
;
5344 // Determine predecessor, if we can
5345 if( it
!= aTxBxSort
.begin() )
5347 SvxMSDffShapeTxBxSort::iterator tmpIter2
= it
;
5349 SvxMSDffShapeOrder
*pPrevOrder
= *tmpIter2
;
5350 if ((0xFFFF0000 & pOrder
->nTxBxComp
)
5351 == (0xFFFF0000 & pPrevOrder
->nTxBxComp
))
5352 pPrevFlyFormat
= pPrevOrder
->pFly
;
5354 // If successor or predecessor present, insert the
5355 // chain at the FlyFrame Format
5356 if (pNextFlyFormat
|| pPrevFlyFormat
)
5358 aChain
.SetNext( pNextFlyFormat
);
5359 aChain
.SetPrev( pPrevFlyFormat
);
5360 pFlyFormat
->SetFormatAttr( aChain
);
5366 bool isHideRedlines(false);
5370 if( m_xWDop
->fRevMarking
)
5371 eMode
|= RedlineFlags::On
;
5372 isHideRedlines
= !m_xWDop
->fRMView
;
5375 m_aInsertedTables
.DelAndMakeTableFrames();
5376 m_aSectionManager
.InsertSegments();
5382 m_xFormImpl
.reset();
5384 m_xMSDffManager
.reset();
5389 m_xAtnNames
.reset();
5390 m_oSprmParser
.reset();
5391 m_xProgress
.reset();
5393 m_pDataStream
= nullptr;
5394 m_pTableStream
= nullptr;
5397 DeleteAnchorStack();
5399 m_oLastAnchorPos
.reset();//ensure this is deleted before UpdatePageDescs
5400 // ofz#10994 remove any trailing fly paras before processing redlines
5401 m_xWFlyPara
.reset();
5402 // ofz#12660 remove any trailing fly paras before deleting extra paras
5403 m_xSFlyPara
.reset();
5404 // remove extra paragraphs after attribute ctrl
5405 // stacks etc. are destroyed, and before fields
5407 m_aExtraneousParas
.delete_all_from_doc();
5408 m_xRedlineStack
->closeall(*m_pPaM
->GetPoint());
5410 // For i120928,achieve the graphics from the special bookmark with is for graphic bullet
5412 std::vector
<const SwGrfNode
*> vecBulletGrf
;
5413 std::vector
<SwFrameFormat
*> vecFrameFormat
;
5415 IDocumentMarkAccess
* const pMarkAccess
= m_rDoc
.getIDocumentMarkAccess();
5418 IDocumentMarkAccess::const_iterator_t ppBkmk
= pMarkAccess
->findBookmark( "_PictureBullets" );
5419 if ( ppBkmk
!= pMarkAccess
->getBookmarksEnd() &&
5420 IDocumentMarkAccess::GetType(**ppBkmk
) == IDocumentMarkAccess::MarkType::BOOKMARK
)
5422 SwTextNode
* pTextNode
= (*ppBkmk
)->GetMarkStart().GetNode().GetTextNode();
5426 const SwpHints
* pHints
= pTextNode
->GetpSwpHints();
5427 for( size_t nHintPos
= 0; pHints
&& nHintPos
< pHints
->Count(); ++nHintPos
)
5429 const SwTextAttr
*pHt
= pHints
->Get(nHintPos
);
5430 if (pHt
->Which() != RES_TXTATR_FLYCNT
)
5432 const sal_Int32 st
= pHt
->GetStart();
5433 if (st
>= (*ppBkmk
)->GetMarkStart().GetContentIndex())
5435 SwFrameFormat
* pFrameFormat
= pHt
->GetFlyCnt().GetFrameFormat();
5436 vecFrameFormat
.push_back(pFrameFormat
);
5437 const SwNodeIndex
* pNdIdx
= pFrameFormat
->GetContent().GetContentIdx();
5438 const SwNodes
* pNodesArray
= (pNdIdx
!= nullptr)
5439 ? &(pNdIdx
->GetNodes())
5441 const SwGrfNode
*pGrf
= (pNodesArray
!= nullptr)
5442 ? (*pNodesArray
)[pNdIdx
->GetIndex() + 1]->GetGrfNode()
5444 vecBulletGrf
.push_back(pGrf
);
5447 // update graphic bullet information
5448 size_t nCount
= m_xLstManager
->GetWW8LSTInfoNum();
5449 for (size_t i
= 0; i
< nCount
; ++i
)
5451 SwNumRule
* pRule
= m_xLstManager
->GetNumRule(i
);
5452 for (sal_uInt16 j
= 0; j
< MAXLEVEL
; ++j
)
5454 SwNumFormat
aNumFormat(pRule
->Get(j
));
5455 const sal_Int16 nType
= aNumFormat
.GetNumberingType();
5456 const sal_uInt16 nGrfBulletCP
= aNumFormat
.GetGrfBulletCP();
5457 if ( nType
== SVX_NUM_BITMAP
5458 && vecBulletGrf
.size() > nGrfBulletCP
5459 && vecBulletGrf
[nGrfBulletCP
] != nullptr )
5461 Graphic aGraphic
= vecBulletGrf
[nGrfBulletCP
]->GetGrf();
5462 SvxBrushItem
aBrush(aGraphic
, GPOS_AREA
, SID_ATTR_BRUSH
);
5463 const vcl::Font
& aFont
= numfunc::GetDefBulletFont();
5464 int nHeight
= aFont
.GetFontHeight() * 12;
5465 Size
aPrefSize( aGraphic
.GetPrefSize());
5466 if (aPrefSize
.Height() * aPrefSize
.Width() != 0 )
5468 int nWidth
= (nHeight
* aPrefSize
.Width()) / aPrefSize
.Height();
5469 Size
aSize(nWidth
, nHeight
);
5470 aNumFormat
.SetGraphicBrush(&aBrush
, &aSize
);
5474 aNumFormat
.SetNumberingType(SVX_NUM_CHAR_SPECIAL
);
5475 aNumFormat
.SetBulletChar(0x2190);
5477 pRule
->Set( j
, aNumFormat
);
5481 // Remove additional pictures
5482 for (SwFrameFormat
* p
: vecFrameFormat
)
5484 m_rDoc
.getIDocumentLayoutAccess().DelLayoutFormat(p
);
5489 m_xLstManager
.reset();
5492 m_oPosAfterTOC
.reset();
5493 m_xRedlineStack
.reset();
5499 // delete the pam before the call for hide all redlines (Bug 73683)
5501 m_rDoc
.getIDocumentRedlineAccess().SetRedlineFlags(eMode
);
5503 UpdatePageDescs(m_rDoc
, nPageDescOffset
);
5505 // can't set it on the layout or view shell because it doesn't exist yet
5506 m_rDoc
.GetDocumentRedlineManager().SetHideRedlines(isHideRedlines
);
5508 return ERRCODE_NONE
;
5511 ErrCode
SwWW8ImplReader::SetSubStreams(tools::SvRef
<SotStorageStream
> &rTableStream
,
5512 tools::SvRef
<SotStorageStream
> &rDataStream
)
5514 ErrCode nErrRet
= ERRCODE_NONE
;
5515 // 6 stands for "6 OR 7", 7 stands for "ONLY 7"
5516 switch (m_xWwFib
->m_nVersion
)
5520 m_pTableStream
= m_pStrm
;
5521 m_pDataStream
= m_pStrm
;
5526 OSL_ENSURE( m_pStg
, "Version 8 always needs to have a Storage!!" );
5527 nErrRet
= ERR_SWG_READ_ERROR
;
5531 rTableStream
= m_pStg
->OpenSotStream(
5532 m_xWwFib
->m_fWhichTableStm
? OUString(SL::a1Table
) : OUString(SL::a0Table
),
5533 StreamMode::STD_READ
);
5535 m_pTableStream
= rTableStream
.get();
5536 m_pTableStream
->SetEndian( SvStreamEndian::LITTLE
);
5538 rDataStream
= m_pStg
->OpenSotStream(SL::aData
, StreamMode::STD_READ
);
5540 if (rDataStream
.is() && ERRCODE_NONE
== rDataStream
->GetError())
5542 m_pDataStream
= rDataStream
.get();
5543 m_pDataStream
->SetEndian(SvStreamEndian::LITTLE
);
5546 m_pDataStream
= m_pStrm
;
5550 OSL_ENSURE( false, "We forgot to encode nVersion!" );
5551 nErrRet
= ERR_SWG_READ_ERROR
;
5559 SvStream
* MakeTemp(std::optional
<utl::TempFileFast
>& roTempFile
)
5561 roTempFile
.emplace();
5562 return roTempFile
->GetStream(StreamMode::READWRITE
| StreamMode::SHARE_DENYWRITE
);
5565 #define WW_BLOCKSIZE 0x200
5567 void DecryptRC4(msfilter::MSCodec97
& rCtx
, SvStream
&rIn
, SvStream
&rOut
)
5569 const std::size_t nLen
= rIn
.TellEnd();
5572 sal_uInt8 in
[WW_BLOCKSIZE
];
5573 for (std::size_t nI
= 0, nBlock
= 0; nI
< nLen
; nI
+= WW_BLOCKSIZE
, ++nBlock
)
5575 std::size_t nBS
= std::min
<size_t>(nLen
- nI
, WW_BLOCKSIZE
);
5576 nBS
= rIn
.ReadBytes(in
, nBS
);
5577 rCtx
.InitCipher(nBlock
);
5578 rCtx
.Decode(in
, nBS
, in
, nBS
);
5579 rOut
.WriteBytes(in
, nBS
);
5583 void DecryptXOR(msfilter::MSCodec_XorWord95
&rCtx
, SvStream
&rIn
, SvStream
&rOut
)
5585 std::size_t nSt
= rIn
.Tell();
5586 std::size_t nLen
= rIn
.TellEnd();
5591 sal_uInt8 in
[0x4096];
5592 for (std::size_t nI
= nSt
; nI
< nLen
; nI
+= 0x4096)
5594 std::size_t nBS
= std::min
<size_t>(nLen
- nI
, 0x4096 );
5595 nBS
= rIn
.ReadBytes(in
, nBS
);
5596 rCtx
.Decode(in
, nBS
);
5597 rOut
.WriteBytes(in
, nBS
);
5601 // moan, copy and paste :-(
5602 OUString
QueryPasswordForMedium(SfxMedium
& rMedium
)
5606 const SfxItemSet
* pSet
= rMedium
.GetItemSet();
5607 const SfxStringItem
*pPasswordItem
;
5609 if(pSet
&& (pPasswordItem
= pSet
->GetItemIfSet(SID_PASSWORD
)))
5610 aPassw
= pPasswordItem
->GetValue();
5615 uno::Reference
< task::XInteractionHandler
> xHandler( rMedium
.GetInteractionHandler() );
5618 rtl::Reference
<::comphelper::DocPasswordRequest
> pRequest
= new ::comphelper::DocPasswordRequest(
5619 ::comphelper::DocPasswordRequestType::MS
, task::PasswordRequestMode_PASSWORD_ENTER
,
5620 INetURLObject(rMedium
.GetOrigURL())
5621 .GetLastName(INetURLObject::DecodeMechanism::WithCharset
));
5623 xHandler
->handle( pRequest
);
5625 if( pRequest
->isPassword() )
5626 aPassw
= pRequest
->getPassword();
5629 catch( const uno::Exception
& )
5637 uno::Sequence
< beans::NamedValue
> InitXorWord95Codec( ::msfilter::MSCodec_XorWord95
& rCodec
, SfxMedium
& rMedium
, WW8Fib
const * pWwFib
)
5639 uno::Sequence
< beans::NamedValue
> aEncryptionData
;
5640 const SfxUnoAnyItem
* pEncryptionData
= SfxItemSet::GetItem
<SfxUnoAnyItem
>(rMedium
.GetItemSet(), SID_ENCRYPTIONDATA
, false);
5641 if ( pEncryptionData
&& ( pEncryptionData
->GetValue() >>= aEncryptionData
) && !rCodec
.InitCodec( aEncryptionData
) )
5642 aEncryptionData
.realloc( 0 );
5644 if ( !aEncryptionData
.hasElements() )
5646 OUString sUniPassword
= QueryPasswordForMedium( rMedium
);
5648 OString
sPassword(OUStringToOString(sUniPassword
,
5649 WW8Fib::GetFIBCharset(pWwFib
->m_chseTables
, pWwFib
->m_lid
)));
5651 sal_Int32 nLen
= sPassword
.getLength();
5654 sal_uInt8 pPassword
[16];
5655 memcpy(pPassword
, sPassword
.getStr(), nLen
);
5656 memset(pPassword
+nLen
, 0, sizeof(pPassword
)-nLen
);
5658 rCodec
.InitKey( pPassword
);
5659 aEncryptionData
= rCodec
.GetEncryptionData();
5661 // the export supports RC4 algorithm only, so we have to
5662 // generate the related EncryptionData as well, so that Save
5663 // can export the document without asking for a password;
5664 // as result there will be EncryptionData for both algorithms
5665 // in the MediaDescriptor
5666 ::msfilter::MSCodec_Std97 aCodec97
;
5668 rtlRandomPool aRandomPool
= rtl_random_createPool();
5669 sal_uInt8 pDocId
[ 16 ];
5670 rtl_random_getBytes( aRandomPool
, pDocId
, 16 );
5672 rtl_random_destroyPool( aRandomPool
);
5674 sal_uInt16 pStd97Pass
[16] = {};
5675 for( sal_Int32 nChar
= 0; nChar
< nLen
; ++nChar
)
5676 pStd97Pass
[nChar
] = sUniPassword
[nChar
];
5678 aCodec97
.InitKey( pStd97Pass
, pDocId
);
5680 // merge the EncryptionData, there should be no conflicts
5681 ::comphelper::SequenceAsHashMap
aEncryptionHash( aEncryptionData
);
5682 aEncryptionHash
.update( ::comphelper::SequenceAsHashMap( aCodec97
.GetEncryptionData() ) );
5683 aEncryptionHash
>> aEncryptionData
;
5687 return aEncryptionData
;
5690 uno::Sequence
< beans::NamedValue
> Init97Codec(msfilter::MSCodec97
& rCodec
, sal_uInt8
const pDocId
[16], SfxMedium
& rMedium
)
5692 uno::Sequence
< beans::NamedValue
> aEncryptionData
;
5693 const SfxUnoAnyItem
* pEncryptionData
= SfxItemSet::GetItem
<SfxUnoAnyItem
>(rMedium
.GetItemSet(), SID_ENCRYPTIONDATA
, false);
5694 if ( pEncryptionData
&& ( pEncryptionData
->GetValue() >>= aEncryptionData
) && !rCodec
.InitCodec( aEncryptionData
) )
5695 aEncryptionData
.realloc( 0 );
5697 if ( !aEncryptionData
.hasElements() )
5699 OUString sUniPassword
= QueryPasswordForMedium( rMedium
);
5701 sal_Int32 nLen
= sUniPassword
.getLength();
5704 sal_uInt16 pPassword
[16] = {};
5705 for( sal_Int32 nChar
= 0; nChar
< nLen
; ++nChar
)
5706 pPassword
[nChar
] = sUniPassword
[nChar
];
5708 rCodec
.InitKey( pPassword
, pDocId
);
5709 aEncryptionData
= rCodec
.GetEncryptionData();
5713 return aEncryptionData
;
5717 //TO-DO: merge this with lclReadFilepass8_Strong in sc which uses a different
5719 static bool lclReadCryptoAPIHeader(msfilter::RC4EncryptionInfo
&info
, SvStream
&rStream
)
5721 //It is possible there are other variants in existence but these
5722 //are the defaults I get with Word 2013
5724 rStream
.ReadUInt32(info
.header
.flags
);
5725 if (oox::getFlag( info
.header
.flags
, msfilter::ENCRYPTINFO_EXTERNAL
))
5728 sal_uInt32
nHeaderSize(0);
5729 rStream
.ReadUInt32(nHeaderSize
);
5730 sal_uInt32 actualHeaderSize
= sizeof(info
.header
);
5732 if (nHeaderSize
< actualHeaderSize
)
5735 rStream
.ReadUInt32(info
.header
.flags
);
5736 rStream
.ReadUInt32(info
.header
.sizeExtra
);
5737 rStream
.ReadUInt32(info
.header
.algId
);
5738 rStream
.ReadUInt32(info
.header
.algIdHash
);
5739 rStream
.ReadUInt32(info
.header
.keyBits
);
5740 rStream
.ReadUInt32(info
.header
.providedType
);
5741 rStream
.ReadUInt32(info
.header
.reserved1
);
5742 rStream
.ReadUInt32(info
.header
.reserved2
);
5744 rStream
.SeekRel(nHeaderSize
- actualHeaderSize
);
5746 rStream
.ReadUInt32(info
.verifier
.saltSize
);
5747 if (info
.verifier
.saltSize
!= msfilter::SALT_LENGTH
)
5749 rStream
.ReadBytes(&info
.verifier
.salt
, sizeof(info
.verifier
.salt
));
5750 rStream
.ReadBytes(&info
.verifier
.encryptedVerifier
, sizeof(info
.verifier
.encryptedVerifier
));
5752 rStream
.ReadUInt32(info
.verifier
.encryptedVerifierHashSize
);
5753 if (info
.verifier
.encryptedVerifierHashSize
!= RTL_DIGEST_LENGTH_SHA1
)
5755 rStream
.ReadBytes(&info
.verifier
.encryptedVerifierHash
, info
.verifier
.encryptedVerifierHashSize
);
5757 // check flags and algorithm IDs, required are AES128 and SHA-1
5758 if (!oox::getFlag(info
.header
.flags
, msfilter::ENCRYPTINFO_CRYPTOAPI
))
5761 if (oox::getFlag(info
.header
.flags
, msfilter::ENCRYPTINFO_AES
))
5764 if (info
.header
.algId
!= msfilter::ENCRYPT_ALGO_RC4
)
5767 // hash algorithm ID 0 defaults to SHA-1 too
5768 if (info
.header
.algIdHash
!= 0 && info
.header
.algIdHash
!= msfilter::ENCRYPT_HASH_SHA1
)
5774 ErrCode
SwWW8ImplReader::LoadThroughDecryption(WW8Glossary
*pGloss
)
5776 ErrCode nErrRet
= ERRCODE_NONE
;
5778 m_xWwFib
= pGloss
->GetFib();
5780 m_xWwFib
= std::make_shared
<WW8Fib
>(*m_pStrm
, m_nWantedVersion
);
5782 if (m_xWwFib
->m_nFibError
)
5783 nErrRet
= ERR_SWG_READ_ERROR
;
5785 tools::SvRef
<SotStorageStream
> xTableStream
, xDataStream
;
5788 nErrRet
= SetSubStreams(xTableStream
, xDataStream
);
5790 std::optional
<utl::TempFileFast
> oTempMain
;
5791 std::optional
<utl::TempFileFast
> oTempTable
;
5792 std::optional
<utl::TempFileFast
> oTempData
;
5793 SvStream
* pDecryptMain
= nullptr;
5794 SvStream
* pDecryptTable
= nullptr;
5795 SvStream
* pDecryptData
= nullptr;
5797 bool bDecrypt
= false;
5798 enum {RC4CryptoAPI
, RC4
, XOR
, Other
} eAlgo
= Other
;
5799 if (m_xWwFib
->m_fEncrypted
&& !nErrRet
)
5804 if (8 != m_xWwFib
->m_nVersion
)
5808 if (m_xWwFib
->m_nKey
!= 0)
5812 m_pTableStream
->Seek(0);
5813 sal_uInt32
nEncType(0);
5814 m_pTableStream
->ReadUInt32(nEncType
);
5815 if (nEncType
== msfilter::VERSION_INFO_1997_FORMAT
)
5817 else if (nEncType
== msfilter::VERSION_INFO_2007_FORMAT
|| nEncType
== msfilter::VERSION_INFO_2007_FORMAT_SP2
)
5818 eAlgo
= RC4CryptoAPI
;
5826 nErrRet
= ERRCODE_SVX_WRONGPASS
;
5827 SfxMedium
* pMedium
= m_pDocShell
->GetMedium();
5834 nErrRet
= ERRCODE_SVX_READ_FILTER_CRYPT
;
5838 msfilter::MSCodec_XorWord95 aCtx
;
5839 uno::Sequence
< beans::NamedValue
> aEncryptionData
= InitXorWord95Codec(aCtx
, *pMedium
, m_xWwFib
.get());
5841 // if initialization has failed the EncryptionData should be empty
5842 if (aEncryptionData
.hasElements() && aCtx
.VerifyKey(m_xWwFib
->m_nKey
, m_xWwFib
->m_nHash
))
5844 nErrRet
= ERRCODE_NONE
;
5845 pDecryptMain
= MakeTemp(oTempMain
);
5848 size_t nUnencryptedHdr
=
5849 (8 == m_xWwFib
->m_nVersion
) ? 0x44 : 0x34;
5850 std::unique_ptr
<sal_uInt8
[]> pIn(new sal_uInt8
[nUnencryptedHdr
]);
5851 nUnencryptedHdr
= m_pStrm
->ReadBytes(pIn
.get(), nUnencryptedHdr
);
5852 pDecryptMain
->WriteBytes(pIn
.get(), nUnencryptedHdr
);
5855 DecryptXOR(aCtx
, *m_pStrm
, *pDecryptMain
);
5857 if (!m_pTableStream
|| m_pTableStream
== m_pStrm
)
5858 m_pTableStream
= pDecryptMain
;
5861 pDecryptTable
= MakeTemp(oTempTable
);
5862 DecryptXOR(aCtx
, *m_pTableStream
, *pDecryptTable
);
5863 m_pTableStream
= pDecryptTable
;
5866 if (!m_pDataStream
|| m_pDataStream
== m_pStrm
)
5867 m_pDataStream
= pDecryptMain
;
5870 pDecryptData
= MakeTemp(oTempData
);
5871 DecryptXOR(aCtx
, *m_pDataStream
, *pDecryptData
);
5872 m_pDataStream
= pDecryptData
;
5875 pMedium
->GetItemSet()->ClearItem( SID_PASSWORD
);
5876 pMedium
->GetItemSet()->Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA
, uno::Any( aEncryptionData
) ) );
5883 std::unique_ptr
<msfilter::MSCodec97
> xCtx
;
5884 msfilter::RC4EncryptionInfo info
;
5885 bool bCouldReadHeaders
;
5889 xCtx
.reset(new msfilter::MSCodec_Std97
);
5890 assert(sizeof(info
.verifier
.encryptedVerifierHash
) >= RTL_DIGEST_LENGTH_MD5
);
5892 checkRead(*m_pTableStream
, info
.verifier
.salt
, sizeof(info
.verifier
.salt
)) &&
5893 checkRead(*m_pTableStream
, info
.verifier
.encryptedVerifier
, sizeof(info
.verifier
.encryptedVerifier
)) &&
5894 checkRead(*m_pTableStream
, info
.verifier
.encryptedVerifierHash
, RTL_DIGEST_LENGTH_MD5
);
5898 xCtx
.reset(new msfilter::MSCodec_CryptoAPI
);
5899 bCouldReadHeaders
= lclReadCryptoAPIHeader(info
, *m_pTableStream
);
5902 // if initialization has failed the EncryptionData should be empty
5903 uno::Sequence
< beans::NamedValue
> aEncryptionData
;
5904 if (bCouldReadHeaders
)
5905 aEncryptionData
= Init97Codec(*xCtx
, info
.verifier
.salt
, *pMedium
);
5907 nErrRet
= ERRCODE_SVX_READ_FILTER_CRYPT
;
5908 if (aEncryptionData
.hasElements() && xCtx
->VerifyKey(info
.verifier
.encryptedVerifier
,
5909 info
.verifier
.encryptedVerifierHash
))
5911 nErrRet
= ERRCODE_NONE
;
5913 pDecryptMain
= MakeTemp(oTempMain
);
5916 std::size_t nUnencryptedHdr
= 0x44;
5917 std::unique_ptr
<sal_uInt8
[]> pIn(new sal_uInt8
[nUnencryptedHdr
]);
5918 nUnencryptedHdr
= m_pStrm
->ReadBytes(pIn
.get(), nUnencryptedHdr
);
5920 DecryptRC4(*xCtx
, *m_pStrm
, *pDecryptMain
);
5922 pDecryptMain
->Seek(0);
5923 pDecryptMain
->WriteBytes(pIn
.get(), nUnencryptedHdr
);
5926 pDecryptTable
= MakeTemp(oTempTable
);
5927 DecryptRC4(*xCtx
, *m_pTableStream
, *pDecryptTable
);
5928 m_pTableStream
= pDecryptTable
;
5930 if (!m_pDataStream
|| m_pDataStream
== m_pStrm
)
5931 m_pDataStream
= pDecryptMain
;
5934 pDecryptData
= MakeTemp(oTempData
);
5935 DecryptRC4(*xCtx
, *m_pDataStream
, *pDecryptData
);
5936 m_pDataStream
= pDecryptData
;
5939 pMedium
->GetItemSet()->ClearItem( SID_PASSWORD
);
5940 pMedium
->GetItemSet()->Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA
, uno::Any( aEncryptionData
) ) );
5947 if (nErrRet
== ERRCODE_NONE
)
5949 m_pStrm
= pDecryptMain
;
5951 m_xWwFib
= std::make_shared
<WW8Fib
>(*m_pStrm
, m_nWantedVersion
);
5952 if (m_xWwFib
->m_nFibError
)
5953 nErrRet
= ERR_SWG_READ_ERROR
;
5958 nErrRet
= CoreLoad(pGloss
);
5968 void SwWW8ImplReader::SetOutlineStyles()
5970 // If we are inserted into a document then don't clobber existing outline
5972 sal_uInt16 nOutlineStyleListLevelWithAssignment
= 0;
5975 ww8::ParaStyles
aOutLined(sw::util::GetParaStyles(m_rDoc
));
5976 sw::util::SortByAssignedOutlineStyleListLevel(aOutLined
);
5977 ww8::ParaStyles::reverse_iterator aEnd
= aOutLined
.rend();
5978 for ( ww8::ParaStyles::reverse_iterator aIter
= aOutLined
.rbegin(); aIter
< aEnd
; ++aIter
)
5980 if ((*aIter
)->IsAssignedToListLevelOfOutlineStyle())
5981 nOutlineStyleListLevelWithAssignment
|= 1 << (*aIter
)->GetAssignedOutlineStyleLevel();
5987 // Check applied WW8 list styles at WW8 Built-In Heading Styles
5988 // - Choose the list style which occurs most often as the one which provides
5989 // the list level properties for the Outline Style.
5990 // - Populate temporary list of WW8 Built-In Heading Styles for further
5992 std::vector
<SwWW8StyInf
*> aWW8BuiltInHeadingStyles
;
5994 sal_uInt16 nStyle
= 0;
5995 std::map
<const SwNumRule
*, int> aWW8ListStyleCounts
;
5996 std::map
<const SwNumRule
*, bool> aPreventUseAsChapterNumbering
;
5997 for (SwWW8StyInf
& rSI
: m_vColl
)
5999 // Copy inherited numbering info since LO drops inheritance after ChapterNumbering
6000 // and only applies listLevel via style with the selected ChapterNumbering LFO.
6001 bool bReRegister
= false;
6002 if (rSI
.m_nBase
&& rSI
.m_nBase
< m_vColl
.size()
6003 && m_vColl
[rSI
.m_nBase
].HasWW8OutlineLevel())
6005 if (rSI
.m_nLFOIndex
== USHRT_MAX
)
6007 rSI
.m_nLFOIndex
= m_vColl
[rSI
.m_nBase
].m_nLFOIndex
;
6009 // When ANYTHING is wrong or strange, prohibit eligibility for ChapterNumbering.
6010 // A style never inherits numbering from Chapter Numbering.
6011 if (rSI
.m_nLFOIndex
!= USHRT_MAX
)
6013 const SwNumRule
* pNumRule
= m_vColl
[rSI
.m_nBase
].m_pOutlineNumrule
;
6015 aPreventUseAsChapterNumbering
[pNumRule
] = true;
6018 if (rSI
.m_nListLevel
== MAXLEVEL
)
6019 rSI
.m_nListLevel
= m_vColl
[rSI
.m_nBase
].m_nListLevel
;
6020 if (rSI
.mnWW8OutlineLevel
== MAXLEVEL
)
6021 rSI
.mnWW8OutlineLevel
= m_vColl
[rSI
.m_nBase
].mnWW8OutlineLevel
;
6025 // Undefined listLevel is treated as the first level with valid numbering rule.
6026 if (rSI
.m_nLFOIndex
< USHRT_MAX
&& rSI
.m_nListLevel
== MAXLEVEL
)
6028 rSI
.m_nListLevel
= 0;
6033 RegisterNumFormatOnStyle(nStyle
);
6035 ++nStyle
; // increment before the first "continue";
6037 if (!rSI
.m_bColl
|| !rSI
.IsWW8BuiltInHeadingStyle() || !rSI
.HasWW8OutlineLevel())
6042 // When ANYTHING is wrong or strange, prohibit eligibility for ChapterNumbering.
6043 if (rSI
.IsOutlineNumbered() && rSI
.m_nListLevel
!= rSI
.mnWW8OutlineLevel
)
6045 aPreventUseAsChapterNumbering
[rSI
.m_pOutlineNumrule
] = true;
6048 aWW8BuiltInHeadingStyles
.push_back(&rSI
);
6050 const SwNumRule
* pWW8ListStyle
= rSI
.GetOutlineNumrule();
6051 if (pWW8ListStyle
!= nullptr)
6053 std::map
<const SwNumRule
*, int>::iterator aCountIter
6054 = aWW8ListStyleCounts
.find(pWW8ListStyle
);
6055 if (aCountIter
== aWW8ListStyleCounts
.end())
6057 aWW8ListStyleCounts
[pWW8ListStyle
] = 1;
6061 ++(aCountIter
->second
);
6066 int nCurrentMaxCount
= 0;
6067 for (const auto& rEntry
: aWW8ListStyleCounts
)
6069 if (aPreventUseAsChapterNumbering
[rEntry
.first
])
6072 if (rEntry
.second
> nCurrentMaxCount
)
6074 nCurrentMaxCount
= rEntry
.second
;
6075 m_pChosenWW8OutlineStyle
= rEntry
.first
;
6080 // - set list level properties of Outline Style - ODF's list style applied
6081 // by default to headings
6082 // - assign corresponding Heading Paragraph Styles to the Outline Style
6083 // - If a heading Paragraph Styles is not applying the WW8 list style which
6084 // had been chosen as
6085 // the one which provides the list level properties for the Outline Style,
6086 // its assignment to
6087 // the Outline Style is removed. A potential applied WW8 list style is
6088 // assigned directly and
6089 // its default outline level is applied.
6090 SwNumRule
aOutlineRule(*m_rDoc
.GetOutlineNumRule());
6091 if (m_pChosenWW8OutlineStyle
)
6093 for (int i
= 0; i
< WW8ListManager::nMaxLevel
; ++i
)
6095 // Don't clobber existing outline levels.
6096 const sal_uInt16 nLevel
= 1 << i
;
6097 if (!(nOutlineStyleListLevelWithAssignment
& nLevel
))
6098 aOutlineRule
.Set(i
, m_pChosenWW8OutlineStyle
->Get(i
));
6102 for (const SwWW8StyInf
* pStyleInf
: aWW8BuiltInHeadingStyles
)
6104 const sal_uInt16 nOutlineStyleListLevelOfWW8BuiltInHeadingStyle
6105 = 1 << pStyleInf
->mnWW8OutlineLevel
;
6106 if (nOutlineStyleListLevelOfWW8BuiltInHeadingStyle
6107 & nOutlineStyleListLevelWithAssignment
)
6112 // in case that there are more styles on this level ignore them
6113 nOutlineStyleListLevelWithAssignment
6114 |= nOutlineStyleListLevelOfWW8BuiltInHeadingStyle
;
6116 SwTextFormatColl
* pTextFormatColl
= static_cast<SwTextFormatColl
*>(pStyleInf
->m_pFormat
);
6117 if (pStyleInf
->GetOutlineNumrule() != m_pChosenWW8OutlineStyle
6118 || (pStyleInf
->m_nListLevel
< WW8ListManager::nMaxLevel
6119 && pStyleInf
->mnWW8OutlineLevel
!= pStyleInf
->m_nListLevel
))
6121 // WW8 Built-In Heading Style does not apply the chosen one.
6122 // --> delete assignment to OutlineStyle, but keep its current
6124 pTextFormatColl
->DeleteAssignmentToListLevelOfOutlineStyle();
6125 // Apply existing WW8 list style a normal list style at the
6127 if (pStyleInf
->GetOutlineNumrule() != nullptr)
6129 pTextFormatColl
->SetFormatAttr(
6130 SwNumRuleItem(pStyleInf
->GetOutlineNumrule()->GetName()));
6132 // apply default outline level of WW8 Built-in Heading Style
6133 const sal_uInt8 nOutlineLevel
6134 = SwWW8StyInf::WW8OutlineLevelToOutlinelevel(
6135 pStyleInf
->mnWW8OutlineLevel
);
6136 pTextFormatColl
->SetFormatAttr(
6137 SfxUInt16Item(RES_PARATR_OUTLINELEVEL
, nOutlineLevel
));
6141 pTextFormatColl
->AssignToListLevelOfOutlineStyle(
6142 pStyleInf
->mnWW8OutlineLevel
);
6146 if (m_pChosenWW8OutlineStyle
)
6148 m_rDoc
.SetOutlineNumRule(aOutlineRule
);
6152 const OUString
* SwWW8ImplReader::GetAnnotationAuthor(sal_uInt16 nIdx
)
6154 if (!m_xAtnNames
&& m_xWwFib
->m_lcbGrpStAtnOwners
)
6156 // Determine authors: can be found in the TableStream
6157 m_xAtnNames
.emplace();
6158 SvStream
& rStrm
= *m_pTableStream
;
6160 auto nOldPos
= rStrm
.Tell();
6161 bool bValidPos
= checkSeek(rStrm
, m_xWwFib
->m_fcGrpStAtnOwners
);
6164 tools::Long nRead
= 0, nCount
= m_xWwFib
->m_lcbGrpStAtnOwners
;
6165 while (nRead
< nCount
&& rStrm
.good())
6169 m_xAtnNames
->push_back(read_uInt8_PascalString(rStrm
,
6170 RTL_TEXTENCODING_MS_1252
));
6171 nRead
+= m_xAtnNames
->rbegin()->getLength() + 1; // Length + sal_uInt8 count
6175 m_xAtnNames
->push_back(read_uInt16_PascalString(rStrm
));
6176 // Unicode: double the length + sal_uInt16 count
6177 nRead
+= (m_xAtnNames
->rbegin()->getLength() + 1)*2;
6181 rStrm
.Seek( nOldPos
);
6184 const OUString
*pRet
= nullptr;
6185 if (m_xAtnNames
&& nIdx
< m_xAtnNames
->size())
6186 pRet
= &((*m_xAtnNames
)[nIdx
]);
6190 void SwWW8ImplReader::GetSmartTagInfo(SwFltRDFMark
& rMark
)
6192 if (!m_pSmartTagData
&& m_xWwFib
->m_lcbFactoidData
)
6194 m_pSmartTagData
.reset(new WW8SmartTagData
);
6195 m_pSmartTagData
->Read(*m_pTableStream
, m_xWwFib
->m_fcFactoidData
, m_xWwFib
->m_lcbFactoidData
);
6198 if (!m_pSmartTagData
)
6201 // Check if the handle is a valid smart tag bookmark index.
6202 size_t nIndex
= rMark
.GetHandle();
6203 if (nIndex
>= m_pSmartTagData
->m_aPropBags
.size())
6206 // Check if the smart tag bookmark refers to a valid factoid type.
6207 const MSOPropertyBag
& rPropertyBag
= m_pSmartTagData
->m_aPropBags
[rMark
.GetHandle()];
6208 auto& rFactoidTypes
= m_pSmartTagData
->m_aPropBagStore
.m_aFactoidTypes
;
6209 auto itPropertyBag
= std::find_if(rFactoidTypes
.begin(), rFactoidTypes
.end(),
6210 [&rPropertyBag
](const MSOFactoidType
& rType
) { return rType
.m_nId
== rPropertyBag
.m_nId
; });
6211 if (itPropertyBag
== rFactoidTypes
.end())
6214 // Check if the factoid is an RDF one.
6215 const MSOFactoidType
& rFactoidType
= *itPropertyBag
;
6216 if (rFactoidType
.m_aUri
!= "http://www.w3.org/1999/02/22-rdf-syntax-ns#")
6219 // Finally put the relevant attributes to the mark.
6220 std::vector
< std::pair
<OUString
, OUString
> > aAttributes
;
6221 for (const MSOProperty
& rProperty
: rPropertyBag
.m_aProperties
)
6225 if (rProperty
.m_nKey
< m_pSmartTagData
->m_aPropBagStore
.m_aStringTable
.size())
6226 aKey
= m_pSmartTagData
->m_aPropBagStore
.m_aStringTable
[rProperty
.m_nKey
];
6227 if (rProperty
.m_nValue
< m_pSmartTagData
->m_aPropBagStore
.m_aStringTable
.size())
6228 aValue
= m_pSmartTagData
->m_aPropBagStore
.m_aStringTable
[rProperty
.m_nValue
];
6229 if (!aKey
.isEmpty() && !aValue
.isEmpty())
6230 aAttributes
.emplace_back(aKey
, aValue
);
6232 rMark
.SetAttributes(std::move(aAttributes
));
6235 ErrCode
SwWW8ImplReader::LoadDoc(WW8Glossary
*pGloss
)
6237 ErrCode nErrRet
= ERRCODE_NONE
;
6240 static const char* aNames
[ 13 ] = {
6241 "WinWord/WW", "WinWord/WW8", "WinWord/WWFT",
6242 "WinWord/WWFLX", "WinWord/WWFLY",
6244 "WinWord/WWFA0", "WinWord/WWFA1", "WinWord/WWFA2",
6245 "WinWord/WWFB0", "WinWord/WWFB1", "WinWord/WWFB2",
6246 "WinWord/RegardHindiDigits"
6248 sal_uInt64 aVal
[ 13 ];
6250 SwFilterOptions
aOpt( 13, aNames
, aVal
);
6252 m_nIniFlags
= aVal
[ 0 ];
6253 m_nIniFlags1
= aVal
[ 1 ];
6254 // Moves Flys by x twips to the right or left
6255 m_nIniFlyDx
= aVal
[ 3 ];
6256 m_nIniFlyDy
= aVal
[ 4 ];
6258 m_nFieldFlags
= aVal
[ 5 ];
6259 m_nFieldTagAlways
[0] = aVal
[ 6 ];
6260 m_nFieldTagAlways
[1] = aVal
[ 7 ];
6261 m_nFieldTagAlways
[2] = aVal
[ 8 ];
6262 m_nFieldTagBad
[0] = aVal
[ 9 ];
6263 m_nFieldTagBad
[1] = aVal
[ 10 ];
6264 m_nFieldTagBad
[2] = aVal
[ 11 ];
6265 m_bRegardHindiDigits
= aVal
[ 12 ] > 0;
6268 sal_uInt16
nMagic(0);
6269 m_pStrm
->ReadUInt16( nMagic
);
6271 // Remember: 6 means "6 OR 7", 7 means "JUST 7"
6272 switch (m_nWantedVersion
)
6277 0xa59b != nMagic
&& 0xa59c != nMagic
&&
6278 0xa5dc != nMagic
&& 0xa5db != nMagic
&&
6279 (nMagic
< 0xa697 || nMagic
> 0xa699)
6282 // Test for own 97 fake!
6283 if (m_pStg
&& 0xa5ec == nMagic
)
6285 sal_uInt64 nCurPos
= m_pStrm
->Tell();
6286 if (checkSeek(*m_pStrm
, nCurPos
+ 2))
6288 sal_uInt32
nfcMin(0);
6289 m_pStrm
->ReadUInt32( nfcMin
);
6290 if (0x300 != nfcMin
)
6291 nErrRet
= ERR_WW6_NO_WW6_FILE_ERR
;
6293 m_pStrm
->Seek( nCurPos
);
6296 nErrRet
= ERR_WW6_NO_WW6_FILE_ERR
;
6300 if (0xa5ec != nMagic
)
6301 nErrRet
= ERR_WW8_NO_WW8_FILE_ERR
;
6304 nErrRet
= ERR_WW8_NO_WW8_FILE_ERR
;
6305 OSL_ENSURE( false, "We forgot to encode nVersion!" );
6310 nErrRet
= LoadThroughDecryption(pGloss
);
6312 m_rDoc
.PropagateOutlineRule();
6317 extern "C" SAL_DLLPUBLIC_EXPORT Reader
* ImportDOC()
6319 return new WW8Reader
;
6324 class FontCacheGuard
6334 bool TestImportDOC(SvStream
&rStream
, const OUString
&rFltName
)
6336 FontCacheGuard aFontCacheGuard
;
6337 std::unique_ptr
<Reader
> xReader(ImportDOC());
6339 tools::SvRef
<SotStorage
> xStorage
;
6340 xReader
->m_pStream
= &rStream
;
6341 if (rFltName
!= "WW6")
6345 xStorage
= tools::SvRef
<SotStorage
>(new SotStorage(rStream
));
6346 if (xStorage
->GetError())
6353 xReader
->m_pStorage
= xStorage
.get();
6355 xReader
->SetFltName(rFltName
);
6357 SwGlobals::ensure();
6359 SfxObjectShellLock
xDocSh(new SwDocShell(SfxObjectCreateMode::INTERNAL
));
6360 xDocSh
->DoInitNew();
6361 SwDoc
*pD
= static_cast<SwDocShell
*>((&xDocSh
))->GetDoc();
6363 SwPaM
aPaM(pD
->GetNodes().GetEndOfContent(), SwNodeOffset(-1));
6364 pD
->SetInReading(true);
6365 bool bRet
= xReader
->Read(*pD
, OUString(), aPaM
, OUString()) == ERRCODE_NONE
;
6366 pD
->SetInReading(false);
6371 extern "C" SAL_DLLPUBLIC_EXPORT
bool TestImportWW8(SvStream
&rStream
)
6373 return TestImportDOC(rStream
, "CWW8");
6376 extern "C" SAL_DLLPUBLIC_EXPORT
bool TestImportWW6(SvStream
&rStream
)
6378 return TestImportDOC(rStream
, "CWW6");
6381 extern "C" SAL_DLLPUBLIC_EXPORT
bool TestImportWW2(SvStream
&rStream
)
6383 return TestImportDOC(rStream
, "WW6");
6386 ErrCode
WW8Reader::OpenMainStream( tools::SvRef
<SotStorageStream
>& rRef
, sal_uInt16
& rBuffSize
)
6388 ErrCode nRet
= ERR_SWG_READ_ERROR
;
6389 OSL_ENSURE(m_pStorage
, "Where is my Storage?");
6390 rRef
= m_pStorage
->OpenSotStream( "WordDocument", StreamMode::READ
| StreamMode::SHARE_DENYALL
);
6394 if( ERRCODE_NONE
== rRef
->GetError() )
6396 sal_uInt16 nOld
= rRef
->GetBufferSize();
6397 rRef
->SetBufferSize( rBuffSize
);
6399 nRet
= ERRCODE_NONE
;
6402 nRet
= rRef
->GetError();
6407 static void lcl_getListOfStreams(SotStorage
* pStorage
, comphelper::SequenceAsHashMap
& aStreamsData
, std::u16string_view sPrefix
)
6409 SvStorageInfoList aElements
;
6410 pStorage
->FillInfoList(&aElements
);
6411 for (const auto & aElement
: aElements
)
6413 OUString sStreamFullName
= sPrefix
.size() ? OUString::Concat(sPrefix
) + "/" + aElement
.GetName() : aElement
.GetName();
6414 if (aElement
.IsStorage())
6416 tools::SvRef
<SotStorage
> xSubStorage
= pStorage
->OpenSotStorage(aElement
.GetName(), StreamMode::STD_READ
| StreamMode::SHARE_DENYALL
);
6417 lcl_getListOfStreams(xSubStorage
.get(), aStreamsData
, sStreamFullName
);
6422 tools::SvRef
<SotStorageStream
> rStream
= pStorage
->OpenSotStream(aElement
.GetName(), StreamMode::READ
| StreamMode::SHARE_DENYALL
);
6425 sal_Int32 nStreamSize
= rStream
->GetSize();
6426 css::uno::Sequence
< sal_Int8
> oData
;
6427 oData
.realloc(nStreamSize
);
6428 sal_Int32 nReadBytes
= rStream
->ReadBytes(oData
.getArray(), nStreamSize
);
6429 if (nStreamSize
== nReadBytes
)
6430 aStreamsData
[sStreamFullName
] <<= oData
;
6436 ErrCode
WW8Reader::DecryptDRMPackage()
6438 // We have DRM encrypted storage. We should try to decrypt it first, if we can
6439 uno::Sequence
< uno::Any
> aArguments
;
6440 uno::Reference
<uno::XComponentContext
> xComponentContext(comphelper::getProcessComponentContext());
6441 uno::Reference
< packages::XPackageEncryption
> xPackageEncryption(
6442 xComponentContext
->getServiceManager()->createInstanceWithArgumentsAndContext(
6443 "com.sun.star.comp.oox.crypto.DRMDataSpace", aArguments
, xComponentContext
), uno::UNO_QUERY
);
6445 if (!xPackageEncryption
.is())
6447 // We do not know how to decrypt this
6448 return ERRCODE_IO_ACCESSDENIED
;
6451 comphelper::SequenceAsHashMap aStreamsData
;
6452 lcl_getListOfStreams(m_pStorage
.get(), aStreamsData
, u
"");
6455 uno::Sequence
<beans::NamedValue
> aStreams
= aStreamsData
.getAsConstNamedValueList();
6456 if (!xPackageEncryption
->readEncryptionInfo(aStreams
))
6458 // We failed with decryption
6459 return ERRCODE_IO_ACCESSDENIED
;
6462 tools::SvRef
<SotStorageStream
> rContentStream
= m_pStorage
->OpenSotStream("\011DRMContent", StreamMode::READ
| StreamMode::SHARE_DENYALL
);
6463 if (!rContentStream
.is())
6465 return ERRCODE_IO_NOTEXISTS
;
6468 mDecodedStream
= std::make_shared
<SvMemoryStream
>();
6470 uno::Reference
<io::XInputStream
> xInputStream(new utl::OSeekableInputStreamWrapper(rContentStream
.get(), false));
6471 uno::Reference
<io::XOutputStream
> xDecryptedStream(new utl::OSeekableOutputStreamWrapper(*mDecodedStream
));
6473 if (!xPackageEncryption
->decrypt(xInputStream
, xDecryptedStream
))
6475 // We failed with decryption
6476 return ERRCODE_IO_ACCESSDENIED
;
6479 mDecodedStream
->Seek(0);
6481 // Further reading is done from new document
6482 m_pStorage
= new SotStorage(*mDecodedStream
);
6484 // Set the media descriptor data
6485 uno::Sequence
<beans::NamedValue
> aEncryptionData
= xPackageEncryption
->createEncryptionData("");
6486 m_pMedium
->GetItemSet()->Put(SfxUnoAnyItem(SID_ENCRYPTIONDATA
, uno::Any(aEncryptionData
)));
6488 catch (const std::exception
&)
6490 return ERRCODE_IO_ACCESSDENIED
;
6493 return ERRCODE_NONE
;
6496 ErrCode
WW8Reader::Read(SwDoc
&rDoc
, const OUString
& rBaseURL
, SwPaM
&rPaM
, const OUString
& /* FileName */)
6498 sal_uInt16 nOldBuffSize
= 32768;
6499 bool bNew
= !m_bInsertMode
; // New Doc (no inserting)
6501 tools::SvRef
<SotStorageStream
> refStrm
; // So that no one else can steal the Stream
6502 SvStream
* pIn
= m_pStream
;
6504 ErrCode nRet
= ERRCODE_NONE
;
6505 sal_uInt8 nVersion
= 8;
6507 const OUString sFltName
= GetFltName();
6508 if ( sFltName
=="WW6" )
6514 OSL_ENSURE(false, "WinWord 95 Reader-Read without Stream");
6515 nRet
= ERR_SWG_READ_ERROR
;
6520 if ( sFltName
=="CWW6" )
6522 else if ( sFltName
=="CWW7" )
6525 if( m_pStorage
.is() )
6527 // Check if we have special encrypted content
6528 tools::SvRef
<SotStorageStream
> rRef
= m_pStorage
->OpenSotStream("\006DataSpaces/DataSpaceInfo/\011DRMDataSpace", StreamMode::READ
| StreamMode::SHARE_DENYALL
);
6531 nRet
= DecryptDRMPackage();
6533 nRet
= OpenMainStream(refStrm
, nOldBuffSize
);
6534 pIn
= refStrm
.get();
6538 OSL_ENSURE(false, "WinWord 95/97 Reader-Read without Storage");
6539 nRet
= ERR_SWG_READ_ERROR
;
6545 std::unique_ptr
<SwWW8ImplReader
> pRdr(new SwWW8ImplReader(nVersion
, m_pStorage
.get(), pIn
, rDoc
,
6546 rBaseURL
, bNew
, m_bSkipImages
, *rPaM
.GetPoint()));
6549 rPaM
.GetBound().nContent
.Assign(nullptr, 0);
6550 rPaM
.GetBound(false).nContent
.Assign(nullptr, 0);
6554 nRet
= pRdr
->LoadDoc();
6556 catch( const std::exception
& )
6558 nRet
= ERR_WW8_NO_WW8_FILE_ERR
;
6563 refStrm
->SetBufferSize( nOldBuffSize
);
6575 SwReaderType
WW8Reader::GetReaderType()
6577 return SwReaderType::Storage
| SwReaderType::Stream
;
6580 bool WW8Reader::HasGlossaries() const
6585 bool WW8Reader::ReadGlossaries(SwTextBlocks
& rBlocks
, bool bSaveRelFiles
) const
6589 WW8Reader
*pThis
= const_cast<WW8Reader
*>(this);
6591 sal_uInt16 nOldBuffSize
= 32768;
6592 tools::SvRef
<SotStorageStream
> refStrm
;
6593 if (!pThis
->OpenMainStream(refStrm
, nOldBuffSize
))
6595 WW8Glossary
aGloss( refStrm
, 8, m_pStorage
.get() );
6596 bRet
= aGloss
.Load( rBlocks
, bSaveRelFiles
);
6601 bool SwMSDffManager::GetOLEStorageName(sal_uInt32 nOLEId
, OUString
& rStorageName
,
6602 tools::SvRef
<SotStorage
>& rSrcStorage
, uno::Reference
< embed::XStorage
>& rDestStorage
) const
6606 sal_Int32 nPictureId
= 0;
6607 if (m_rReader
.m_pStg
)
6609 // Via the TextBox-PLCF we get the right char Start-End positions
6610 // We should then find the EmbeddedField and the corresponding Sprms
6612 // We only need the Sprm for the Picture Id.
6613 sal_uInt64 nOldPos
= m_rReader
.m_pStrm
->Tell();
6615 // #i32596# - consider return value of method
6616 // <rReader.GetTxbxTextSttEndCp(..)>. If it returns false, method
6617 // wasn't successful. Thus, continue in this case.
6618 // Note: Ask MM for initialization of <nStartCp> and <nEndCp>.
6619 // Note: Ask MM about assertions in method <rReader.GetTxbxTextSttEndCp(..)>.
6620 WW8_CP nStartCp
, nEndCp
;
6621 if ( m_rReader
.m_bDrawCpOValid
&& m_rReader
.GetTxbxTextSttEndCp(nStartCp
, nEndCp
,
6622 o3tl::narrowing
<sal_uInt16
>((nOLEId
>> 16) & 0xFFFF),
6623 o3tl::narrowing
<sal_uInt16
>(nOLEId
& 0xFFFF)) )
6625 WW8PLCFxSaveAll aSave
;
6626 m_rReader
.m_xPlcxMan
->SaveAllPLCFx( aSave
);
6628 nStartCp
+= m_rReader
.m_nDrawCpO
;
6629 nEndCp
+= m_rReader
.m_nDrawCpO
;
6630 WW8PLCFx_Cp_FKP
* pChp
= m_rReader
.m_xPlcxMan
->GetChpPLCF();
6631 wwSprmParser
aSprmParser(*m_rReader
.m_xWwFib
);
6632 while (nStartCp
<= nEndCp
&& !nPictureId
)
6634 if (!pChp
->SeekPos( nStartCp
))
6637 pChp
->GetSprms( &aDesc
);
6639 if (aDesc
.nSprmsLen
&& aDesc
.pMemPos
) // Attributes present
6641 auto nLen
= aDesc
.nSprmsLen
;
6642 const sal_uInt8
* pSprm
= aDesc
.pMemPos
;
6644 while (nLen
>= 2 && !nPictureId
)
6646 sal_uInt16 nId
= aSprmParser
.GetSprmId(pSprm
);
6647 sal_Int32 nSL
= aSprmParser
.GetSprmSize(nId
, pSprm
, nLen
);
6650 break; // Not enough Bytes left
6654 nPictureId
= SVBT32ToUInt32(pSprm
+
6655 aSprmParser
.DistanceToData(nId
));
6662 nStartCp
= aDesc
.nEndPos
;
6665 m_rReader
.m_xPlcxMan
->RestoreAllPLCFx( aSave
);
6668 m_rReader
.m_pStrm
->Seek( nOldPos
);
6674 rStorageName
+= OUString::number(nPictureId
);
6675 rSrcStorage
= m_rReader
.m_pStg
->OpenSotStorage(SL::aObjectPool
);
6676 if (!m_rReader
.m_pDocShell
)
6679 rDestStorage
= m_rReader
.m_pDocShell
->GetStorage();
6685 * When reading a single Box (which possibly is part of a group), we do
6686 * not yet have enough information to decide whether we need it as a TextField
6688 * So convert all of them as a precaution.
6689 * FIXME: Actually implement this!
6691 bool SwMSDffManager::ShapeHasText(sal_uLong
, sal_uLong
) const
6696 bool SwWW8ImplReader::InEqualOrHigherApo(int nLvl
) const
6700 // #i60827# - check size of <maApos> to assure that <maApos.begin() + nLvl> can be performed.
6701 if ( sal::static_int_cast
< sal_Int32
>(nLvl
) >= sal::static_int_cast
< sal_Int32
>(m_aApos
.size()) )
6705 auto aIter
= std::find(m_aApos
.begin() + nLvl
, m_aApos
.end(), true);
6706 return aIter
!= m_aApos
.end();
6709 bool SwWW8ImplReader::InEqualApo(int nLvl
) const
6711 // If we are in a table, see if an apo was inserted at the level below the table.
6714 if (nLvl
< 0 || o3tl::make_unsigned(nLvl
) >= m_aApos
.size())
6716 return m_aApos
[nLvl
];
6721 Position::Position(const SwPosition
&rPos
)
6722 : maPtNode(rPos
.GetNode()), mnPtContent(rPos
.GetContentIndex())
6726 Position::operator SwPosition() const
6728 return SwPosition(maPtNode
, maPtNode
.GetNode().GetContentNode(), mnPtContent
);
6732 SwMacroInfo::SwMacroInfo()
6733 : SdrObjUserData( SdrInventor::ScOrSwDraw
, SW_UD_IMAPDATA
)
6738 SwMacroInfo::~SwMacroInfo()
6742 std::unique_ptr
<SdrObjUserData
> SwMacroInfo::Clone( SdrObject
* /*pObj*/ ) const
6744 return std::unique_ptr
<SdrObjUserData
>(new SwMacroInfo( *this ));
6747 std::unique_ptr
<SfxItemSet
> SwWW8ImplReader::SetCurrentItemSet(std::unique_ptr
<SfxItemSet
> pItemSet
)
6749 std::unique_ptr
<SfxItemSet
> xRet(std::move(m_xCurrentItemSet
));
6750 m_xCurrentItemSet
= std::move(pItemSet
);
6754 void SwWW8ImplReader::NotifyMacroEventRead()
6756 if (m_bNotifyMacroEventRead
)
6758 uno::Reference
<frame::XModel
> const xModel(m_rDoc
.GetDocShell()->GetBaseModel());
6759 comphelper::DocumentInfo::notifyMacroEventRead(xModel
);
6760 m_bNotifyMacroEventRead
= true;
6763 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */