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/lang/XMultiServiceFactory.hpp>
30 #include <i18nlangtag/languagetag.hxx>
32 #include <unotools/configmgr.hxx>
33 #include <unotools/ucbstreamhelper.hxx>
34 #include <rtl/random.h>
35 #include <rtl/ustring.hxx>
36 #include <rtl/ustrbuf.hxx>
38 #include <sfx2/docinf.hxx>
39 #include <sfx2/request.hxx>
40 #include <sfx2/frame.hxx>
41 #include <tools/urlobj.hxx>
42 #include <unotools/tempfile.hxx>
44 #include <comphelper/docpasswordrequest.hxx>
45 #include <comphelper/documentinfo.hxx>
46 #include <comphelper/propertysequence.hxx>
48 #include <editeng/outlobj.hxx>
49 #include <editeng/brushitem.hxx>
50 #include <editeng/formatbreakitem.hxx>
51 #include <editeng/tstpitem.hxx>
52 #include <editeng/ulspitem.hxx>
53 #include <editeng/langitem.hxx>
54 #include <editeng/opaqitem.hxx>
55 #include <editeng/charhiddenitem.hxx>
56 #include <editeng/fontitem.hxx>
57 #include <editeng/editeng.hxx>
58 #include <svx/unoapi.hxx>
59 #include <svx/svdoole2.hxx>
60 #include <svx/svdoashp.hxx>
61 #include <svx/svxerr.hxx>
62 #include <filter/msfilter/mscodec.hxx>
63 #include <svx/svdmodel.hxx>
64 #include <svx/xflclit.hxx>
65 #include <svx/sdasitm.hxx>
66 #include <svx/sdtagitm.hxx>
67 #include <svx/sdtcfitm.hxx>
68 #include <svx/sdtditm.hxx>
69 #include <svx/sdtmfitm.hxx>
70 #include <unotools/fltrcfg.hxx>
73 #include <fmtinfmt.hxx>
75 #include <fmthdft.hxx>
76 #include <fmtcntnt.hxx>
77 #include <fmtcnct.hxx>
78 #include <fmtanchr.hxx>
79 #include <fmtpdsc.hxx>
80 #include <ftninfo.hxx>
84 #include <pagedesc.hxx>
86 #include <poolfmt.hxx>
87 #include <fmtclbl.hxx>
88 #include <section.hxx>
90 #include <IDocumentFieldsAccess.hxx>
91 #include <IDocumentLayoutAccess.hxx>
92 #include <IDocumentMarkAccess.hxx>
93 #include <IDocumentStylePoolAccess.hxx>
94 #include <IDocumentExternalData.hxx>
95 #include <../../core/inc/DocumentRedlineManager.hxx>
96 #include <docufld.hxx>
97 #include <swfltopt.hxx>
99 #include <viewopt.hxx>
100 #include <shellres.hxx>
101 #include <mdiexp.hxx>
103 #include <swtable.hxx>
104 #include <fchrfmt.hxx>
105 #include <charfmt.hxx>
106 #include <unocrsr.hxx>
107 #include <IDocumentSettingAccess.hxx>
108 #include "sprmids.hxx"
110 #include <fltini.hxx>
112 #include "writerwordglue.hxx"
115 #include <editeng/editids.hrc>
116 #include <txtflcnt.hxx>
117 #include <fmtflcnt.hxx>
118 #include <txatbase.hxx>
120 #include "ww8par2.hxx"
122 #include <com/sun/star/beans/PropertyAttribute.hpp>
123 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
124 #include <com/sun/star/document/XViewDataSupplier.hpp>
125 #include <com/sun/star/document/IndexedPropertyValues.hpp>
126 #include <svl/itemiter.hxx>
128 #include <comphelper/processfactory.hxx>
129 #include <basic/basmgr.hxx>
131 #include "ww8toolbar.hxx"
132 #include <osl/file.hxx>
134 #include <breakit.hxx>
136 #if OSL_DEBUG_LEVEL > 1
138 #include <dbgoutsw.hxx>
141 #include <svx/hlnkitem.hxx>
142 #include <sfx2/docfile.hxx>
144 #include "WW8Sttbf.hxx"
145 #include "WW8FibData.hxx"
146 #include <unordered_set>
149 using namespace ::com::sun::star
;
150 using namespace sw::util
;
151 using namespace sw::types
;
152 using namespace nsHdFtFlags
;
154 #include <com/sun/star/i18n/BreakIterator.hpp>
155 #include <com/sun/star/i18n/ScriptType.hpp>
156 #include <unotools/pathoptions.hxx>
157 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
159 #include <com/sun/star/script/vba/XVBACompatibility.hpp>
160 #include <comphelper/sequenceashashmap.hxx>
161 #include <oox/ole/vbaproject.hxx>
162 #include <oox/ole/olestorage.hxx>
163 #include <comphelper/storagehelper.hxx>
164 #include <sfx2/DocumentMetadataAccess.hxx>
165 #include <tools/diagnose_ex.h>
167 static SwMacroInfo
* GetMacroInfo( SdrObject
* pObj
)
171 sal_uInt16 nCount
= pObj
->GetUserDataCount();
172 for( sal_uInt16 i
= 0; i
< nCount
; i
++ )
174 SdrObjUserData
* pData
= pObj
->GetUserData( i
);
175 if( pData
&& pData
->GetInventor() == SdrInventor::ScOrSwDraw
176 && pData
->GetId() == SW_UD_IMAPDATA
)
178 return dynamic_cast<SwMacroInfo
*>(pData
);
181 SwMacroInfo
* pData
= new SwMacroInfo
;
182 pObj
->AppendUserData(std::unique_ptr
<SdrObjUserData
>(pData
));
189 static void lclGetAbsPath(OUString
& rPath
, sal_uInt16 nLevel
, SwDocShell
const * pDocShell
)
191 OUStringBuffer aTmpStr
;
194 aTmpStr
.append("../");
197 if (!aTmpStr
.isEmpty())
198 aTmpStr
.append(rPath
);
202 if (!aTmpStr
.isEmpty())
204 bool bWasAbs
= false;
205 rPath
= pDocShell
->GetMedium()->GetURLObject().smartRel2Abs( aTmpStr
.makeStringAndClear(), bWasAbs
).GetMainURL( INetURLObject::DecodeMechanism::NONE
);
206 // full path as stored in SvxURLField must be encoded
212 void lclIgnoreUString32(SvStream
& rStrm
)
214 sal_uInt32
nChars(0);
215 rStrm
.ReadUInt32(nChars
);
217 rStrm
.SeekRel(nChars
);
221 void SwWW8ImplReader::ReadEmbeddedData(SvStream
& rStrm
, SwDocShell
const * pDocShell
, struct HyperLinksTable
& hlStr
)
224 // const sal_uInt16 WW8_ID_HLINK = 0x01B8;
225 const sal_uInt32 WW8_HLINK_BODY
= 0x00000001; /// Contains file link or URL.
226 const sal_uInt32 WW8_HLINK_ABS
= 0x00000002; /// Absolute path.
227 const sal_uInt32 WW8_HLINK_DESCR
= 0x00000014; /// Description.
228 const sal_uInt32 WW8_HLINK_MARK
= 0x00000008; /// Text mark.
229 const sal_uInt32 WW8_HLINK_FRAME
= 0x00000080; /// Target frame.
230 const sal_uInt32 WW8_HLINK_UNC
= 0x00000100; /// UNC path.
232 //sal_uInt8 maGuidStdLink[ 16 ] ={
233 // 0xD0, 0xC9, 0xEA, 0x79, 0xF9, 0xBA, 0xCE, 0x11, 0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B };
235 sal_uInt8
const aGuidUrlMoniker
[ 16 ] = {
236 0xE0, 0xC9, 0xEA, 0x79, 0xF9, 0xBA, 0xCE, 0x11, 0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B };
238 sal_uInt8
const aGuidFileMoniker
[ 16 ] = {
239 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 };
242 sal_uInt32
nFlags(0);
244 rStrm
.ReadBytes(aGuid
, 16);
246 rStrm
.ReadUInt32( nFlags
);
248 sal_uInt16 nLevel
= 0; // counter for level to climb down in path
249 std::unique_ptr
< OUString
> xLongName
; // link / file name
250 std::unique_ptr
< OUString
> xShortName
; // 8.3-representation of file name
251 std::unique_ptr
< OUString
> xTextMark
; // text mark
253 // description (ignore)
254 if( ::get_flag( nFlags
, WW8_HLINK_DESCR
) )
255 lclIgnoreUString32( rStrm
);
258 if( ::get_flag( nFlags
, WW8_HLINK_FRAME
) )
260 hlStr
.tarFrame
= read_uInt32_lenPrefixed_uInt16s_ToOUString(rStrm
);
264 if( ::get_flag( nFlags
, WW8_HLINK_UNC
) )
266 // MS-OSHARED: An unsigned integer that specifies the number of Unicode characters in the
267 // string field, including the null-terminating character.
268 sal_uInt32
nStrLen(0);
269 rStrm
.ReadUInt32(nStrLen
);
272 xLongName
.reset(new OUString(read_uInt16s_ToOUString(rStrm
, nStrLen
- 1)));
273 rStrm
.SeekRel(sizeof(sal_Unicode
)); // skip null-byte at end
275 lclGetAbsPath( *xLongName
, 0 , pDocShell
);
278 else if( ::get_flag( nFlags
, WW8_HLINK_BODY
) )
280 rStrm
.ReadBytes(aGuid
, 16);
282 if( memcmp(aGuid
, aGuidFileMoniker
, 16) == 0 )
284 rStrm
.ReadUInt16( nLevel
);
285 // MS-OSHARED: An unsigned integer that specifies the number of
286 // ANSI characters in ansiPath, including the terminating NULL character
287 sal_uInt32 nUnits
= 0;
288 rStrm
.ReadUInt32(nUnits
);
291 OString
sStr(read_uInt8s_ToOString(rStrm
, nUnits
- 1));
292 rStrm
.SeekRel(sizeof(sal_uInt8
)); // skip null-byte at end
293 xShortName
.reset(new OUString(sStr
.getStr(), sStr
.getLength(), GetCharSetFromLanguage()));
297 sal_uInt32
nStrLen(0);
298 rStrm
.ReadUInt32( nStrLen
);
302 rStrm
.ReadUInt32( nStrLen
);
305 // MS-OSHARED: This array MUST not include a terminating NULL character.
306 xLongName
.reset(new OUString(read_uInt16s_ToOUString(rStrm
, nStrLen
)));
307 lclGetAbsPath( *xLongName
, nLevel
, pDocShell
);
310 lclGetAbsPath( *xShortName
, nLevel
, pDocShell
);
312 else if( memcmp(aGuid
, aGuidUrlMoniker
, 16) == 0 )
314 // MS-OSHARED: An unsigned integer that specifies the size of this
315 // structure in bytes, excluding the size of the length field. The
316 // value of this field MUST be ... the byte size of the url
317 // field (including the terminating NULL character)
318 sal_uInt32
nStrLen(0);
319 rStrm
.ReadUInt32( nStrLen
);
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
.get())
343 xLongName
.reset( new OUString
);
344 *xLongName
+= *xShortName
;
346 else if (!xLongName
&& xTextMark
.get())
347 xLongName
.reset( new OUString
);
353 if (xLongName
->isEmpty())
354 *xTextMark
= xTextMark
->replace('!', '.');
355 *xLongName
+= "#" + *xTextMark
;
357 hlStr
.hLinkAddr
= *xLongName
;
361 class BasicProjImportHelper
363 SwDocShell
& mrDocShell
;
364 uno::Reference
< uno::XComponentContext
> mxCtx
;
366 explicit BasicProjImportHelper( SwDocShell
& rShell
) : mrDocShell( rShell
)
368 mxCtx
= comphelper::getProcessComponentContext();
370 bool import( const uno::Reference
< io::XInputStream
>& rxIn
);
371 OUString
getProjectName();
374 bool BasicProjImportHelper::import( const uno::Reference
< io::XInputStream
>& rxIn
)
379 oox::ole::OleStorage
root( mxCtx
, rxIn
, false );
380 oox::StorageRef vbaStg
= root
.openSubStorage( "Macros" , false );
383 oox::ole::VbaProject
aVbaPrj( mxCtx
, mrDocShell
.GetModel(), "Writer" );
384 bRet
= aVbaPrj
.importVbaProject( *vbaStg
);
387 catch( const uno::Exception
& )
394 OUString
BasicProjImportHelper::getProjectName()
396 OUString
sProjName( "Standard" );
397 uno::Reference
< beans::XPropertySet
> xProps( mrDocShell
.GetModel(), uno::UNO_QUERY
);
402 uno::Reference
< script::vba::XVBACompatibility
> xVBA( xProps
->getPropertyValue( "BasicLibraries" ), uno::UNO_QUERY_THROW
);
403 sProjName
= xVBA
->getProjectName();
406 catch( const uno::Exception
& )
413 class Sttb
: public TBBase
419 SBBItem() : cchData(0){}
425 std::vector
< SBBItem
> dataItems
;
427 Sttb(Sttb
const&) = delete;
428 Sttb
& operator=(Sttb
const&) = delete;
433 bool Read(SvStream
&rS
) override
;
434 OUString
getStringAtIndex( sal_uInt32
);
444 bool Sttb::Read( SvStream
& rS
)
446 SAL_INFO("sw.ww8", "stream pos " << rS
.Tell());
448 rS
.ReadUInt16( fExtend
).ReadUInt16( cData
).ReadUInt16( cbExtra
);
451 //if they are all going to be empty strings, how many could there be
452 const size_t nMaxPossibleRecords
= rS
.remainingSize() / sizeof(sal_uInt16
);
453 if (cData
> nMaxPossibleRecords
)
455 for ( sal_Int32 index
= 0; index
< cData
; ++index
)
458 rS
.ReadUInt16( aItem
.cchData
);
459 aItem
.data
= read_uInt16s_ToOUString(rS
, aItem
.cchData
);
460 dataItems
.push_back( aItem
);
467 Sttb::getStringAtIndex( sal_uInt32 index
)
470 if ( index
< dataItems
.size() )
471 aRet
= dataItems
[ index
].data
;
476 SwMSDffManager::SwMSDffManager( SwWW8ImplReader
& rRdr
, bool bSkipImages
)
477 : SvxMSDffManager(*rRdr
.m_pTableStream
, rRdr
.GetBaseURL(), rRdr
.m_xWwFib
->m_fcDggInfo
,
478 rRdr
.m_pDataStream
, nullptr, 0, COL_WHITE
, rRdr
.m_pStrm
, bSkipImages
),
479 rReader(rRdr
), pFallbackStream(nullptr)
481 SetSvxMSDffSettings( GetSvxMSDffSettings() );
482 nSvxMSDffOLEConvFlags
= SwMSDffManager::GetFilterFlags();
485 sal_uInt32
SwMSDffManager::GetFilterFlags()
487 sal_uInt32
nFlags(0);
488 const SvtFilterOptions
& rOpt
= SvtFilterOptions::Get();
489 if (rOpt
.IsMathType2Math())
490 nFlags
|= OLE_MATHTYPE_2_STARMATH
;
491 if (rOpt
.IsExcel2Calc())
492 nFlags
|= OLE_EXCEL_2_STARCALC
;
493 if (rOpt
.IsPowerPoint2Impress())
494 nFlags
|= OLE_POWERPOINT_2_STARIMPRESS
;
495 if (rOpt
.IsWinWord2Writer())
496 nFlags
|= OLE_WINWORD_2_STARWRITER
;
501 * I would like to override the default OLE importing to add a test
502 * and conversion of OCX controls from their native OLE type into our
503 * native nonOLE Form Control Objects.
505 // #i32596# - consider new parameter <_nCalledByGroup>
506 SdrObject
* SwMSDffManager::ImportOLE( sal_uInt32 nOLEId
,
508 const tools::Rectangle
& rBoundRect
,
509 const tools::Rectangle
& rVisArea
,
510 const int _nCalledByGroup
) const
512 // #i32596# - no import of OLE object, if it's inside a group.
513 // NOTE: This can be undone, if grouping of Writer fly frames is possible or
514 // if drawing OLE objects are allowed in Writer.
515 if ( _nCalledByGroup
> 0 )
520 SdrObject
* pRet
= nullptr;
521 OUString sStorageName
;
522 tools::SvRef
<SotStorage
> xSrcStg
;
523 uno::Reference
< embed::XStorage
> xDstStg
;
524 if( GetOLEStorageName( nOLEId
, sStorageName
, xSrcStg
, xDstStg
))
526 tools::SvRef
<SotStorage
> xSrc
= xSrcStg
->OpenSotStorage( sStorageName
);
527 OSL_ENSURE(rReader
.m_xFormImpl
, "No Form Implementation!");
528 css::uno::Reference
< css::drawing::XShape
> xShape
;
529 if ( (!(rReader
.m_bIsHeader
|| rReader
.m_bIsFooter
)) &&
530 rReader
.m_xFormImpl
->ReadOCXStream(xSrc
,&xShape
,true))
532 pRet
= GetSdrObjectFromXShape(xShape
);
536 ErrCode nError
= ERRCODE_NONE
;
537 pRet
= CreateSdrOLEFromStorage(
547 nSvxMSDffOLEConvFlags
,
548 css::embed::Aspects::MSOLE_CONTENT
,
549 rReader
.GetBaseURL());
555 void SwMSDffManager::DisableFallbackStream()
557 OSL_ENSURE(!pFallbackStream
,
558 "if you're recursive, you're broken");
559 pFallbackStream
= pStData2
;
560 aOldEscherBlipCache
= aEscherBlipCache
;
561 aEscherBlipCache
.clear();
565 void SwMSDffManager::EnableFallbackStream()
567 pStData2
= pFallbackStream
;
568 aEscherBlipCache
= aOldEscherBlipCache
;
569 aOldEscherBlipCache
.clear();
570 pFallbackStream
= nullptr;
573 sal_uInt16
SwWW8ImplReader::GetToggleAttrFlags() const
575 return m_xCtrlStck
? m_xCtrlStck
->GetToggleAttrFlags() : 0;
578 sal_uInt16
SwWW8ImplReader::GetToggleBiDiAttrFlags() const
580 return m_xCtrlStck
? m_xCtrlStck
->GetToggleBiDiAttrFlags() : 0;
583 void SwWW8ImplReader::SetToggleAttrFlags(sal_uInt16 nFlags
)
586 m_xCtrlStck
->SetToggleAttrFlags(nFlags
);
589 void SwWW8ImplReader::SetToggleBiDiAttrFlags(sal_uInt16 nFlags
)
592 m_xCtrlStck
->SetToggleBiDiAttrFlags(nFlags
);
595 SdrObject
* SwMSDffManager::ProcessObj(SvStream
& rSt
,
596 DffObjData
& rObjData
,
597 SvxMSDffClientData
& rData
,
598 tools::Rectangle
& rTextRect
,
602 if( !rTextRect
.IsEmpty() )
604 SvxMSDffImportData
& rImportData
= static_cast<SvxMSDffImportData
&>(rData
);
605 std::unique_ptr
<SvxMSDffImportRec
> pImpRec(new SvxMSDffImportRec
);
607 // fill Import Record with data
608 pImpRec
->nShapeId
= rObjData
.nShapeId
;
609 pImpRec
->eShapeType
= rObjData
.eShapeType
;
611 rObjData
.bClientAnchor
= maShapeRecords
.SeekToContent( rSt
,
612 DFF_msofbtClientAnchor
,
613 SEEK_FROM_CURRENT_AND_RESTART
);
614 if( rObjData
.bClientAnchor
)
615 ProcessClientAnchor( rSt
,
616 maShapeRecords
.Current()->nRecLen
,
617 pImpRec
->pClientAnchorBuffer
, pImpRec
->nClientAnchorLen
);
619 rObjData
.bClientData
= maShapeRecords
.SeekToContent( rSt
,
620 DFF_msofbtClientData
,
621 SEEK_FROM_CURRENT_AND_RESTART
);
622 if( rObjData
.bClientData
)
623 ProcessClientData( rSt
,
624 maShapeRecords
.Current()->nRecLen
,
625 pImpRec
->pClientDataBuffer
, pImpRec
->nClientDataLen
);
627 // process user (== Winword) defined parameters in 0xF122 record
628 // #i84783# - set special value to determine, if property is provided or not.
629 pImpRec
->nLayoutInTableCell
= 0xFFFFFFFF;
631 if( maShapeRecords
.SeekToContent( rSt
,
633 SEEK_FROM_CURRENT_AND_RESTART
)
634 && maShapeRecords
.Current()->nRecLen
)
636 sal_uInt32 nBytesLeft
= maShapeRecords
.Current()->nRecLen
;
637 auto nAvailableBytes
= rSt
.remainingSize();
638 if (nBytesLeft
> nAvailableBytes
)
640 SAL_WARN("sw.ww8", "Document claimed to have shape record of " << nBytesLeft
<< " bytes, but only " << nAvailableBytes
<< " available");
641 nBytesLeft
= nAvailableBytes
;
643 while( 5 < nBytesLeft
)
646 rSt
.ReadUInt16(nPID
);
647 sal_uInt32
nUDData(0);
648 rSt
.ReadUInt32(nUDData
);
653 case 0x038F: pImpRec
->nXAlign
= nUDData
; break;
655 pImpRec
->nXRelTo
= nUDData
;
657 case 0x0391: pImpRec
->nYAlign
= nUDData
; break;
659 pImpRec
->nYRelTo
= nUDData
;
661 case 0x03BF: pImpRec
->nLayoutInTableCell
= nUDData
; break;
663 // This seems to correspond to o:hrpct from .docx (even including
664 // the difference that it's in 0.1% even though the .docx spec
666 pImpRec
->relativeHorizontalWidth
= nUDData
;
669 // And this is really just a guess, but a mere presence of this
670 // flag makes a horizontal rule be as wide as the page (unless
671 // overridden by something), so it probably matches o:hr from .docx.
672 pImpRec
->isHorizontalRule
= true;
679 // Text Frame also Title or Outline
680 sal_uInt32 nTextId
= GetPropertyValue( DFF_Prop_lTxid
, 0 );
683 SfxItemSet
aSet( pSdrModel
->GetItemPool() );
685 // Originally anything that as a mso_sptTextBox was created as a
686 // textbox, this was changed to be created as a simple
687 // rect to keep impress happy. For the rest of us we'd like to turn
688 // it back into a textbox again.
689 bool bIsSimpleDrawingTextBox
= (pImpRec
->eShapeType
== mso_sptTextBox
);
690 if (!bIsSimpleDrawingTextBox
)
693 // a) it's a simple text object or
694 // b) it's a rectangle with text and square wrapping.
695 bIsSimpleDrawingTextBox
=
697 (pImpRec
->eShapeType
== mso_sptTextSimple
) ||
699 (pImpRec
->eShapeType
== mso_sptRectangle
)
700 && ShapeHasText(pImpRec
->nShapeId
, rObjData
.rSpHd
.GetRecBegFilePos() )
705 // Distance of Textbox to its surrounding Autoshape
706 sal_Int32 nTextLeft
= GetPropertyValue( DFF_Prop_dxTextLeft
, 91440);
707 sal_Int32 nTextRight
= GetPropertyValue( DFF_Prop_dxTextRight
, 91440 );
708 sal_Int32 nTextTop
= GetPropertyValue( DFF_Prop_dyTextTop
, 45720 );
709 sal_Int32 nTextBottom
= GetPropertyValue( DFF_Prop_dyTextBottom
, 45720 );
711 ScaleEmu( nTextLeft
);
712 ScaleEmu( nTextRight
);
713 ScaleEmu( nTextTop
);
714 ScaleEmu( nTextBottom
);
716 sal_Int32 nTextRotationAngle
=0;
717 bool bVerticalText
= false;
718 if ( IsProperty( DFF_Prop_txflTextFlow
) )
720 MSO_TextFlow eTextFlow
= static_cast<MSO_TextFlow
>(GetPropertyValue(
721 DFF_Prop_txflTextFlow
, 0) & 0xFFFF);
725 nTextRotationAngle
= 9000;
729 nTextRotationAngle
= 27000;
732 bVerticalText
= true;
735 bVerticalText
= true;
736 nTextRotationAngle
= 9000;
744 if (nTextRotationAngle
)
746 if (nTextRotationAngle
== 9000)
748 long nWidth
= rTextRect
.GetWidth();
749 rTextRect
.SetRight( rTextRect
.Left() + rTextRect
.GetHeight() );
750 rTextRect
.SetBottom( rTextRect
.Top() + nWidth
);
752 sal_Int32 nOldTextLeft
= nTextLeft
;
753 sal_Int32 nOldTextRight
= nTextRight
;
754 sal_Int32 nOldTextTop
= nTextTop
;
755 sal_Int32 nOldTextBottom
= nTextBottom
;
757 nTextLeft
= nOldTextBottom
;
758 nTextRight
= nOldTextTop
;
759 nTextTop
= nOldTextLeft
;
760 nTextBottom
= nOldTextRight
;
762 else if (nTextRotationAngle
== 27000)
764 long nWidth
= rTextRect
.GetWidth();
765 rTextRect
.SetRight( rTextRect
.Left() + rTextRect
.GetHeight() );
766 rTextRect
.SetBottom( rTextRect
.Top() + nWidth
);
768 sal_Int32 nOldTextLeft
= nTextLeft
;
769 sal_Int32 nOldTextRight
= nTextRight
;
770 sal_Int32 nOldTextTop
= nTextTop
;
771 sal_Int32 nOldTextBottom
= nTextBottom
;
773 nTextLeft
= nOldTextTop
;
774 nTextRight
= nOldTextBottom
;
775 nTextTop
= nOldTextRight
;
776 nTextBottom
= nOldTextLeft
;
780 if (bIsSimpleDrawingTextBox
)
782 SdrObject::Free( pObj
);
783 pObj
= new SdrRectObj(
789 // The vertical paragraph justification are contained within the
790 // BoundRect so calculate it here
791 tools::Rectangle
aNewRect(rTextRect
);
792 aNewRect
.AdjustBottom( -(nTextTop
+ nTextBottom
) );
793 aNewRect
.AdjustRight( -(nTextLeft
+ nTextRight
) );
795 // Only if it's a simple Textbox, Writer can replace the Object
796 // with a Frame, else
797 if( bIsSimpleDrawingTextBox
)
799 std::shared_ptr
<SvxMSDffShapeInfo
> const xTmpRec(
800 new SvxMSDffShapeInfo(0, pImpRec
->nShapeId
));
802 SvxMSDffShapeInfos_ById::const_iterator
const it
=
803 GetShapeInfos()->find(xTmpRec
);
804 if (it
!= GetShapeInfos()->end())
806 SvxMSDffShapeInfo
& rInfo
= **it
;
807 pImpRec
->bReplaceByFly
= rInfo
.bReplaceByFly
;
810 ApplyAttributes(rSt
, aSet
, rObjData
);
813 if (GetPropertyValue(DFF_Prop_FitTextToShape
, 0) & 2)
815 aSet
.Put( makeSdrTextAutoGrowHeightItem( true ) );
816 aSet
.Put( makeSdrTextMinFrameHeightItem(
817 aNewRect
.Bottom() - aNewRect
.Top() ) );
818 aSet
.Put( makeSdrTextMinFrameWidthItem(
819 aNewRect
.Right() - aNewRect
.Left() ) );
823 aSet
.Put( makeSdrTextAutoGrowHeightItem( false ) );
824 aSet
.Put( makeSdrTextAutoGrowWidthItem( false ) );
827 switch ( static_cast<MSO_WrapMode
>(GetPropertyValue( DFF_Prop_WrapText
, mso_wrapSquare
)) )
830 aSet
.Put( makeSdrTextAutoGrowWidthItem( true ) );
831 pImpRec
->bAutoWidth
= true;
833 case mso_wrapByPoints
:
834 aSet
.Put( makeSdrTextContourFrameItem( true ) );
840 // Set distances on Textbox's margins
841 aSet
.Put( makeSdrTextLeftDistItem( nTextLeft
) );
842 aSet
.Put( makeSdrTextRightDistItem( nTextRight
) );
843 aSet
.Put( makeSdrTextUpperDistItem( nTextTop
) );
844 aSet
.Put( makeSdrTextLowerDistItem( nTextBottom
) );
845 pImpRec
->nDxTextLeft
= nTextLeft
;
846 pImpRec
->nDyTextTop
= nTextTop
;
847 pImpRec
->nDxTextRight
= nTextRight
;
848 pImpRec
->nDyTextBottom
= nTextBottom
;
850 // Taking the correct default (which is mso_anchorTop)
851 sal_uInt32 eTextAnchor
=
852 GetPropertyValue( DFF_Prop_anchorText
, mso_anchorTop
);
854 SdrTextVertAdjust eTVA
= bVerticalText
855 ? SDRTEXTVERTADJUST_BLOCK
856 : SDRTEXTVERTADJUST_CENTER
;
857 SdrTextHorzAdjust eTHA
= bVerticalText
858 ? SDRTEXTHORZADJUST_CENTER
859 : SDRTEXTHORZADJUST_BLOCK
;
861 switch( eTextAnchor
)
866 eTHA
= SDRTEXTHORZADJUST_RIGHT
;
868 eTVA
= SDRTEXTVERTADJUST_TOP
;
871 case mso_anchorTopCentered
:
874 eTHA
= SDRTEXTHORZADJUST_RIGHT
;
876 eTVA
= SDRTEXTVERTADJUST_TOP
;
879 case mso_anchorMiddle
:
881 case mso_anchorMiddleCentered
:
883 case mso_anchorBottom
:
886 eTHA
= SDRTEXTHORZADJUST_LEFT
;
888 eTVA
= SDRTEXTVERTADJUST_BOTTOM
;
891 case mso_anchorBottomCentered
:
894 eTHA
= SDRTEXTHORZADJUST_LEFT
;
896 eTVA
= SDRTEXTVERTADJUST_BOTTOM
;
903 aSet
.Put( SdrTextVertAdjustItem( eTVA
) );
904 aSet
.Put( SdrTextHorzAdjustItem( eTHA
) );
908 pObj
->SetMergedItemSet(aSet
);
912 SdrTextObj
*pTextObj
= dynamic_cast< SdrTextObj
* >(pObj
);
914 pTextObj
->SetVerticalWriting(true);
917 if ( bIsSimpleDrawingTextBox
)
919 if ( nTextRotationAngle
)
921 long nMinWH
= rTextRect
.GetWidth() < rTextRect
.GetHeight() ?
922 rTextRect
.GetWidth() : rTextRect
.GetHeight();
924 Point
aPivot(rTextRect
.TopLeft());
925 aPivot
.AdjustX(nMinWH
);
926 aPivot
.AdjustY(nMinWH
);
927 double a
= nTextRotationAngle
* F_PI18000
;
928 pObj
->NbcRotate(aPivot
, nTextRotationAngle
, sin(a
), cos(a
));
932 if ( ( ( rObjData
.nSpFlags
& ShapeFlag::FlipV
) || mnFix16Angle
|| nTextRotationAngle
) && dynamic_cast< SdrObjCustomShape
* >( pObj
) )
934 SdrObjCustomShape
* pCustomShape
= dynamic_cast< SdrObjCustomShape
* >( pObj
);
937 double fExtraTextRotation
= 0.0;
938 if ( mnFix16Angle
&& !( GetPropertyValue( DFF_Prop_FitTextToShape
, 0 ) & 4 ) )
939 { // text is already rotated, we have to take back the object rotation if DFF_Prop_RotateText is false
940 fExtraTextRotation
= -mnFix16Angle
;
942 if ( rObjData
.nSpFlags
& ShapeFlag::FlipV
) // sj: in ppt the text is flipped, whereas in word the text
943 { // remains unchanged, so we have to take back the flipping here
944 fExtraTextRotation
+= 18000.0; // because our core will flip text if the shape is flipped.
946 fExtraTextRotation
+= nTextRotationAngle
;
947 if ( !::basegfx::fTools::equalZero( fExtraTextRotation
) )
949 fExtraTextRotation
/= 100.0;
950 SdrCustomShapeGeometryItem
aGeometryItem( pCustomShape
->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY
) );
951 const OUString
sTextRotateAngle( "TextRotateAngle" );
952 css::beans::PropertyValue aPropVal
;
953 aPropVal
.Name
= sTextRotateAngle
;
954 aPropVal
.Value
<<= fExtraTextRotation
;
955 aGeometryItem
.SetPropertyValue( aPropVal
);
956 pCustomShape
->SetMergedItem( aGeometryItem
);
960 else if ( mnFix16Angle
)
962 // rotate text with shape ?
963 double a
= mnFix16Angle
* F_PI18000
;
964 pObj
->NbcRotate( rObjData
.aBoundRect
.Center(), mnFix16Angle
,
965 sin( a
), cos( a
) );
971 // simple rectangular objects are ignored by ImportObj() :-(
972 // this is OK for Draw but not for Calc and Writer
973 // cause here these objects have a default border
974 pObj
= new SdrRectObj(
978 SfxItemSet
aSet( pSdrModel
->GetItemPool() );
979 ApplyAttributes( rSt
, aSet
, rObjData
);
981 const SfxPoolItem
* pPoolItem
=nullptr;
982 SfxItemState eState
= aSet
.GetItemState( XATTR_FILLCOLOR
,
984 if( SfxItemState::DEFAULT
== eState
)
985 aSet
.Put( XFillColorItem( OUString(), mnDefaultColor
) );
986 pObj
->SetMergedItemSet(aSet
);
989 // Means that fBehindDocument is set
990 if (GetPropertyValue(DFF_Prop_fPrint
, 0) & 0x20)
991 pImpRec
->bDrawHell
= true;
993 pImpRec
->bDrawHell
= false;
994 if (GetPropertyValue(DFF_Prop_fPrint
, 0) & 0x02)
995 pImpRec
->bHidden
= true;
996 pImpRec
->nNextShapeId
= GetPropertyValue( DFF_Prop_hspNext
, 0 );
1000 pImpRec
->aTextId
.nTxBxS
= static_cast<sal_uInt16
>( nTextId
>> 16 );
1001 pImpRec
->aTextId
.nSequence
= static_cast<sal_uInt16
>(nTextId
);
1004 pImpRec
->nDxWrapDistLeft
= GetPropertyValue(
1005 DFF_Prop_dxWrapDistLeft
, 114935 ) / 635;
1006 pImpRec
->nDyWrapDistTop
= GetPropertyValue(
1007 DFF_Prop_dyWrapDistTop
, 0 ) / 635;
1008 pImpRec
->nDxWrapDistRight
= GetPropertyValue(
1009 DFF_Prop_dxWrapDistRight
, 114935 ) / 635;
1010 pImpRec
->nDyWrapDistBottom
= GetPropertyValue(
1011 DFF_Prop_dyWrapDistBottom
, 0 ) / 635;
1012 // 16.16 fraction times total image width or height, as appropriate.
1014 if (SeekToContent(DFF_Prop_pWrapPolygonVertices
, rSt
))
1016 pImpRec
->pWrapPolygon
.reset();
1018 sal_uInt16
nNumElemVert(0), nNumElemMemVert(0), nElemSizeVert(0);
1019 rSt
.ReadUInt16( nNumElemVert
).ReadUInt16( nNumElemMemVert
).ReadUInt16( nElemSizeVert
);
1021 if (nNumElemVert
&& ((nElemSizeVert
== 8) || (nElemSizeVert
== 4)))
1023 //check if there is enough data in the file to make the
1025 bOk
= rSt
.remainingSize() / nElemSizeVert
>= nNumElemVert
;
1029 pImpRec
->pWrapPolygon
.reset( new tools::Polygon(nNumElemVert
) );
1030 for (sal_uInt16 i
= 0; i
< nNumElemVert
; ++i
)
1032 sal_Int32
nX(0), nY(0);
1033 if (nElemSizeVert
== 8)
1034 rSt
.ReadInt32( nX
).ReadInt32( nY
);
1037 sal_Int16
nSmallX(0), nSmallY(0);
1038 rSt
.ReadInt16( nSmallX
).ReadInt16( nSmallY
);
1042 (*(pImpRec
->pWrapPolygon
))[i
].setX( nX
);
1043 (*(pImpRec
->pWrapPolygon
))[i
].setY( nY
);
1048 pImpRec
->nCropFromTop
= GetPropertyValue(
1049 DFF_Prop_cropFromTop
, 0 );
1050 pImpRec
->nCropFromBottom
= GetPropertyValue(
1051 DFF_Prop_cropFromBottom
, 0 );
1052 pImpRec
->nCropFromLeft
= GetPropertyValue(
1053 DFF_Prop_cropFromLeft
, 0 );
1054 pImpRec
->nCropFromRight
= GetPropertyValue(
1055 DFF_Prop_cropFromRight
, 0 );
1057 sal_uInt32 nLineFlags
= GetPropertyValue( DFF_Prop_fNoLineDrawDash
, 0 );
1059 if ( !IsHardAttribute( DFF_Prop_fLine
) &&
1060 pImpRec
->eShapeType
== mso_sptPictureFrame
)
1062 nLineFlags
&= ~0x08;
1065 pImpRec
->eLineStyle
= (nLineFlags
& 8)
1066 ? static_cast<MSO_LineStyle
>(GetPropertyValue(
1069 : MSO_LineStyle(USHRT_MAX
);
1070 pImpRec
->eLineDashing
= static_cast<MSO_LineDashing
>(GetPropertyValue(
1071 DFF_Prop_lineDashing
, mso_lineSolid
));
1073 pImpRec
->nFlags
= rObjData
.nSpFlags
;
1075 if( pImpRec
->nShapeId
)
1077 auto pImpRecTmp
= pImpRec
.get();
1078 // Complement Import Record List
1079 pImpRec
->pObj
= pObj
;
1080 rImportData
.insert(std::move(pImpRec
));
1082 // Complement entry in Z Order List with a pointer to this Object
1083 // Only store objects which are not deep inside the tree
1084 if( ( rObjData
.nCalledByGroup
== 0 )
1086 ( (rObjData
.nSpFlags
& ShapeFlag::Group
)
1087 && (rObjData
.nCalledByGroup
< 2) )
1089 StoreShapeOrder( pImpRecTmp
->nShapeId
,
1090 ( static_cast<sal_uLong
>(pImpRecTmp
->aTextId
.nTxBxS
) << 16 )
1091 + pImpRecTmp
->aTextId
.nSequence
, pObj
);
1097 sal_uInt32 nBufferSize
= GetPropertyValue( DFF_Prop_pihlShape
, 0 );
1098 if( (0 < nBufferSize
) && (nBufferSize
<= 0xFFFF) && SeekToContent( DFF_Prop_pihlShape
, rSt
) )
1100 SvMemoryStream aMemStream
;
1101 struct HyperLinksTable hlStr
;
1102 sal_uInt16 nRawRecId
,nRawRecSize
;
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_uInt8 nStreamSize
= aMemStream
.TellEnd();
1111 aMemStream
.Seek( STREAM_SEEK_TO_BEGIN
);
1112 bool bRet
= 4 <= nStreamSize
;
1114 aMemStream
.ReadUInt16( nRawRecId
).ReadUInt16( nRawRecSize
);
1115 SwDocShell
* pDocShell
= rReader
.m_pDocShell
;
1118 rReader
.ReadEmbeddedData(aMemStream
, pDocShell
, hlStr
);
1122 if (pObj
&& !hlStr
.hLinkAddr
.isEmpty())
1124 SwMacroInfo
* pInfo
= GetMacroInfo( pObj
);
1127 pInfo
->SetShapeId( rObjData
.nShapeId
);
1128 pInfo
->SetHlink( hlStr
.hLinkAddr
);
1129 if (!hlStr
.tarFrame
.isEmpty())
1130 pInfo
->SetTarFrame( hlStr
.tarFrame
);
1131 OUString aNameStr
= GetPropertyString( DFF_Prop_wzName
, rSt
);
1132 if (!aNameStr
.isEmpty())
1133 pInfo
->SetName( aNameStr
);
1142 * Special FastSave - Attributes
1144 void SwWW8ImplReader::Read_StyleCode( sal_uInt16
, const sal_uInt8
* pData
, short nLen
)
1148 m_bCpxStyle
= false;
1151 sal_uInt16 nColl
= 0;
1152 if (m_xWwFib
->GetFIBVersion() <= ww::eWW2
)
1155 nColl
= SVBT16ToUInt16(pData
);
1156 if (nColl
< m_vColl
.size())
1158 SetTextFormatCollAndListLevel( *m_pPaM
, m_vColl
[nColl
] );
1164 * Read_Majority is for Majority (103) and Majority50 (108)
1166 void SwWW8ImplReader::Read_Majority( sal_uInt16
, const sal_uInt8
* , short )
1173 void SwWW8FltControlStack::NewAttr(const SwPosition
& rPos
,
1174 const SfxPoolItem
& rAttr
)
1176 OSL_ENSURE(RES_TXTATR_FIELD
!= rAttr
.Which(), "probably don't want to put"
1177 "fields into the control stack");
1178 OSL_ENSURE(RES_TXTATR_INPUTFIELD
!= rAttr
.Which(), "probably don't want to put"
1179 "input fields into the control stack");
1180 OSL_ENSURE(RES_TXTATR_ANNOTATION
!= rAttr
.Which(), "probably don't want to put"
1181 "annotations into the control stack");
1182 OSL_ENSURE(RES_FLTR_REDLINE
!= rAttr
.Which(), "probably don't want to put"
1183 "redlines into the control stack");
1184 SwFltControlStack::NewAttr(rPos
, rAttr
);
1187 SwFltStackEntry
* SwWW8FltControlStack::SetAttr(const SwPosition
& rPos
, sal_uInt16 nAttrId
,
1188 bool bTstEnde
, long nHand
, bool )
1190 SwFltStackEntry
*pRet
= nullptr;
1191 // Doing a textbox, and using the control stack only as a temporary
1192 // collection point for properties which will are not to be set into
1193 // the real document
1194 if (rReader
.m_xPlcxMan
&& rReader
.m_xPlcxMan
->GetDoingDrawTextBox())
1196 size_t nCnt
= size();
1197 for (size_t i
=0; i
< nCnt
; ++i
)
1199 SwFltStackEntry
& rEntry
= (*this)[i
];
1200 if (nAttrId
== rEntry
.pAttr
->Which())
1202 DeleteAndDestroy(i
--);
1207 else // Normal case, set the attribute into the document
1208 pRet
= SwFltControlStack::SetAttr(rPos
, nAttrId
, bTstEnde
, nHand
);
1212 long GetListFirstLineIndent(const SwNumFormat
&rFormat
)
1214 OSL_ENSURE( rFormat
.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION
,
1215 "<GetListFirstLineIndent> - misusage: position-and-space-mode does not equal LABEL_WIDTH_AND_POSITION" );
1217 SvxAdjust eAdj
= rFormat
.GetNumAdjust();
1218 long nReverseListIndented
;
1219 if (eAdj
== SvxAdjust::Right
)
1220 nReverseListIndented
= -rFormat
.GetCharTextDistance();
1221 else if (eAdj
== SvxAdjust::Center
)
1222 nReverseListIndented
= rFormat
.GetFirstLineOffset()/2;
1224 nReverseListIndented
= rFormat
.GetFirstLineOffset();
1225 return nReverseListIndented
;
1228 static long lcl_GetTrueMargin(const SvxLRSpaceItem
&rLR
, const SwNumFormat
&rFormat
,
1229 long &rFirstLinePos
)
1231 OSL_ENSURE( rFormat
.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION
,
1232 "<lcl_GetTrueMargin> - misusage: position-and-space-mode does not equal LABEL_WIDTH_AND_POSITION" );
1234 const long nBodyIndent
= rLR
.GetTextLeft();
1235 const long nFirstLineDiff
= rLR
.GetTextFirstLineOfst();
1236 rFirstLinePos
= nBodyIndent
+ nFirstLineDiff
;
1238 const auto nPseudoListBodyIndent
= rFormat
.GetAbsLSpace();
1239 const long nReverseListIndented
= GetListFirstLineIndent(rFormat
);
1240 long nExtraListIndent
= nPseudoListBodyIndent
+ nReverseListIndented
;
1242 return std::max
<long>(nExtraListIndent
, 0);
1247 void SyncIndentWithList( SvxLRSpaceItem
&rLR
,
1248 const SwNumFormat
&rFormat
,
1249 const bool bFirstLineOfstSet
,
1250 const bool bLeftIndentSet
)
1252 if ( rFormat
.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION
)
1254 long nWantedFirstLinePos
;
1255 long nExtraListIndent
= lcl_GetTrueMargin(rLR
, rFormat
, nWantedFirstLinePos
);
1256 rLR
.SetTextLeft(nWantedFirstLinePos
- nExtraListIndent
);
1257 rLR
.SetTextFirstLineOfst(0);
1259 else if ( rFormat
.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT
)
1261 if ( !bFirstLineOfstSet
&& bLeftIndentSet
&&
1262 rFormat
.GetFirstLineIndent() != 0 )
1264 rLR
.SetTextFirstLineOfst( rFormat
.GetFirstLineIndent() );
1266 else if ( bFirstLineOfstSet
&& !bLeftIndentSet
&&
1267 rFormat
.GetIndentAt() != 0 )
1269 rLR
.SetTextLeft( rFormat
.GetIndentAt() );
1271 else if (!bFirstLineOfstSet
&& !bLeftIndentSet
)
1273 if ( rFormat
.GetFirstLineIndent() != 0 )
1275 rLR
.SetTextFirstLineOfst( rFormat
.GetFirstLineIndent() );
1277 if ( rFormat
.GetIndentAt() != 0 )
1279 rLR
.SetTextLeft( rFormat
.GetIndentAt() );
1285 const SwNumFormat
* SwWW8FltControlStack::GetNumFormatFromStack(const SwPosition
&rPos
,
1286 const SwTextNode
&rTextNode
)
1288 const SwNumFormat
*pRet
= nullptr;
1289 const SfxPoolItem
*pItem
= GetStackAttr(rPos
, RES_FLTR_NUMRULE
);
1290 if (pItem
&& rTextNode
.GetNumRule())
1292 if (rTextNode
.IsCountedInList())
1294 OUString
sName(static_cast<const SfxStringItem
*>(pItem
)->GetValue());
1295 const SwNumRule
*pRule
= pDoc
->FindNumRulePtr(sName
);
1297 pRet
= GetNumFormatFromSwNumRuleLevel(*pRule
, rTextNode
.GetActualListLevel());
1303 sal_Int32
SwWW8FltControlStack::GetCurrAttrCP() const
1305 return rReader
.GetCurrAttrCP();
1308 bool SwWW8FltControlStack::IsParaEndInCPs(sal_Int32 nStart
,sal_Int32 nEnd
,bool bSdOD
) const
1310 return rReader
.IsParaEndInCPs(nStart
,nEnd
,bSdOD
);
1314 * Clear the para end position recorded in reader intermittently
1315 * for the least impact on loading performance.
1317 void SwWW8FltControlStack::ClearParaEndPosition()
1322 rReader
.ClearParaEndPosition();
1325 bool SwWW8FltControlStack::CheckSdOD(sal_Int32 nStart
,sal_Int32 nEnd
)
1327 return rReader
.IsParaEndInCPs(nStart
,nEnd
);
1330 void SwWW8ReferencedFltEndStack::SetAttrInDoc( const SwPosition
& rTmpPos
,
1331 SwFltStackEntry
& rEntry
)
1333 switch( rEntry
.pAttr
->Which() )
1335 case RES_FLTR_BOOKMARK
:
1337 // suppress insertion of bookmark, which is recognized as an internal bookmark used for table-of-content
1338 // and which is not referenced.
1339 bool bInsertBookmarkIntoDoc
= true;
1341 SwFltBookmark
* pFltBookmark
= dynamic_cast<SwFltBookmark
*>(rEntry
.pAttr
.get());
1342 if ( pFltBookmark
!= nullptr && pFltBookmark
->IsTOCBookmark() )
1344 const OUString
& rName
= pFltBookmark
->GetName();
1345 std::set
< OUString
, SwWW8::ltstr
>::const_iterator aResult
= aReferencedTOCBookmarks
.find(rName
);
1346 if ( aResult
== aReferencedTOCBookmarks
.end() )
1348 bInsertBookmarkIntoDoc
= false;
1351 if ( bInsertBookmarkIntoDoc
)
1353 SwFltEndStack::SetAttrInDoc( rTmpPos
, rEntry
);
1358 SwFltEndStack::SetAttrInDoc( rTmpPos
, rEntry
);
1364 void SwWW8FltControlStack::SetAttrInDoc(const SwPosition
& rTmpPos
,
1365 SwFltStackEntry
& rEntry
)
1367 switch (rEntry
.pAttr
->Which())
1372 Loop over the affected nodes and
1373 a) convert the word style absolute indent to indent relative
1374 to any numbering indent active on the nodes
1375 b) adjust the writer style tabstops relative to the old
1376 paragraph indent to be relative to the new paragraph indent
1378 SwPaM
aRegion(rTmpPos
);
1379 if (rEntry
.MakeRegion(pDoc
, aRegion
, false))
1381 SvxLRSpaceItem
aNewLR( *static_cast<SvxLRSpaceItem
*>(rEntry
.pAttr
.get()) );
1382 sal_uLong nStart
= aRegion
.Start()->nNode
.GetIndex();
1383 sal_uLong nEnd
= aRegion
.End()->nNode
.GetIndex();
1384 for(; nStart
<= nEnd
; ++nStart
)
1386 SwNode
* pNode
= pDoc
->GetNodes()[ nStart
];
1387 if (!pNode
|| !pNode
->IsTextNode())
1390 SwContentNode
* pNd
= static_cast<SwContentNode
*>(pNode
);
1391 SvxLRSpaceItem aOldLR
= static_cast<const SvxLRSpaceItem
&>(pNd
->GetAttr(RES_LR_SPACE
));
1393 SwTextNode
*pTextNode
= static_cast<SwTextNode
*>(pNode
);
1395 const SwNumFormat
* pNum
1396 = GetNumFormatFromStack(*aRegion
.GetPoint(), *pTextNode
);
1399 pNum
= GetNumFormatFromTextNode(*pTextNode
);
1405 const bool bFirstLineIndentSet
=
1406 ( rReader
.m_aTextNodesHavingFirstLineOfstSet
.end() !=
1407 rReader
.m_aTextNodesHavingFirstLineOfstSet
.find( pNode
) );
1409 const bool bLeftIndentSet
=
1410 ( rReader
.m_aTextNodesHavingLeftIndentSet
.end() !=
1411 rReader
.m_aTextNodesHavingLeftIndentSet
.find( pNode
) );
1412 SyncIndentWithList( aNewLR
, *pNum
,
1413 bFirstLineIndentSet
,
1417 if (aNewLR
== aOldLR
)
1420 pNd
->SetAttr(aNewLR
);
1427 case RES_TXTATR_FIELD
:
1428 OSL_ENSURE(false, "What is a field doing in the control stack,"
1429 "probably should have been in the endstack");
1432 case RES_TXTATR_ANNOTATION
:
1433 OSL_ENSURE(false, "What is an annotation doing in the control stack,"
1434 "probably should have been in the endstack");
1437 case RES_TXTATR_INPUTFIELD
:
1438 OSL_ENSURE(false, "What is an input field doing in the control stack,"
1439 "probably should have been in the endstack");
1442 case RES_TXTATR_INETFMT
:
1444 SwPaM
aRegion(rTmpPos
);
1445 if (rEntry
.MakeRegion(pDoc
, aRegion
, false))
1447 SwFrameFormat
*pFrame
;
1448 // If we have just one single inline graphic then
1449 // don't insert a field for the single frame, set
1450 // the frames hyperlink field attribute directly.
1451 if (nullptr != (pFrame
= SwWW8ImplReader::ContainsSingleInlineGraphic(aRegion
)))
1453 const SwFormatINetFormat
*pAttr
= static_cast<const SwFormatINetFormat
*>(
1454 rEntry
.pAttr
.get());
1456 aURL
.SetURL(pAttr
->GetValue(), false);
1457 aURL
.SetTargetFrameName(pAttr
->GetTargetFrame());
1458 pFrame
->SetFormatAttr(aURL
);
1462 pDoc
->getIDocumentContentOperations().InsertPoolItem(aRegion
, *rEntry
.pAttr
);
1468 SwFltControlStack::SetAttrInDoc(rTmpPos
, rEntry
);
1473 const SfxPoolItem
* SwWW8FltControlStack::GetFormatAttr(const SwPosition
& rPos
,
1476 const SfxPoolItem
*pItem
= GetStackAttr(rPos
, nWhich
);
1479 SwContentNode
const*const pNd
= rPos
.nNode
.GetNode().GetContentNode();
1481 pItem
= &pDoc
->GetAttrPool().GetDefaultItem(nWhich
);
1485 If we're hunting for the indent on a paragraph and need to use the
1486 parent style indent, then return the indent in msword format, and
1487 not writer format, because that's the style that the filter works
1490 if (nWhich
== RES_LR_SPACE
)
1492 SfxItemState eState
= SfxItemState::DEFAULT
;
1493 if (const SfxItemSet
*pSet
= pNd
->GetpSwAttrSet())
1494 eState
= pSet
->GetItemState(RES_LR_SPACE
, false);
1495 if (eState
!= SfxItemState::SET
&& rReader
.m_nCurrentColl
< rReader
.m_vColl
.size())
1496 pItem
= rReader
.m_vColl
[rReader
.m_nCurrentColl
].maWordLR
.get();
1500 If we're hunting for a character property, try and exact position
1501 within the text node for lookup
1503 if (pNd
->IsTextNode())
1505 const sal_Int32 nPos
= rPos
.nContent
.GetIndex();
1506 m_xScratchSet
.reset(new SfxItemSet(pDoc
->GetAttrPool(), {{nWhich
, nWhich
}}));
1507 if (pNd
->GetTextNode()->GetParaAttr(*m_xScratchSet
, nPos
, nPos
))
1508 pItem
= m_xScratchSet
->GetItem(nWhich
);
1512 pItem
= &pNd
->GetAttr(nWhich
);
1518 const SfxPoolItem
* SwWW8FltControlStack::GetStackAttr(const SwPosition
& rPos
,
1521 SwFltPosition
aFltPos(rPos
);
1523 size_t nSize
= size();
1526 const SwFltStackEntry
& rEntry
= (*this)[ --nSize
];
1527 if (rEntry
.pAttr
->Which() == nWhich
)
1529 if ( (rEntry
.bOpen
) ||
1531 (rEntry
.m_aMkPos
.m_nNode
<= aFltPos
.m_nNode
) &&
1532 (rEntry
.m_aPtPos
.m_nNode
>= aFltPos
.m_nNode
) &&
1533 (rEntry
.m_aMkPos
.m_nContent
<= aFltPos
.m_nContent
) &&
1534 (rEntry
.m_aPtPos
.m_nContent
> aFltPos
.m_nContent
)
1538 * e.g. half-open range [0-3) so asking for properties at 3
1539 * means props that end at 3 are not included
1542 return rEntry
.pAttr
.get();
1549 bool SwWW8FltRefStack::IsFootnoteEdnBkmField(
1550 const SwFormatField
& rFormatField
,
1553 const SwField
* pField
= rFormatField
.GetField();
1554 sal_uInt16 nSubType
;
1555 if(pField
&& (SwFieldIds::GetRef
== pField
->Which())
1556 && ((REF_FOOTNOTE
== (nSubType
= pField
->GetSubType())) || (REF_ENDNOTE
== nSubType
))
1557 && !static_cast<const SwGetRefField
*>(pField
)->GetSetRefName().isEmpty())
1559 const IDocumentMarkAccess
* const pMarkAccess
= pDoc
->getIDocumentMarkAccess();
1560 IDocumentMarkAccess::const_iterator_t ppBkmk
=
1561 pMarkAccess
->findMark( static_cast<const SwGetRefField
*>(pField
)->GetSetRefName() );
1562 if(ppBkmk
!= pMarkAccess
->getAllMarksEnd())
1564 // find Sequence No of corresponding Foot-/Endnote
1565 rBkmNo
= ppBkmk
- pMarkAccess
->getAllMarksBegin();
1572 void SwWW8FltRefStack::SetAttrInDoc(const SwPosition
& rTmpPos
,
1573 SwFltStackEntry
& rEntry
)
1575 switch (rEntry
.pAttr
->Which())
1578 Look up these in our lists of bookmarks that were changed to
1579 variables, and replace the ref field with a var field, otherwise
1580 do normal (?) strange stuff
1582 case RES_TXTATR_FIELD
:
1583 case RES_TXTATR_ANNOTATION
:
1584 case RES_TXTATR_INPUTFIELD
:
1586 SwNodeIndex
aIdx(rEntry
.m_aMkPos
.m_nNode
, 1);
1587 SwPaM
aPaM(aIdx
, rEntry
.m_aMkPos
.m_nContent
);
1589 SwFormatField
& rFormatField
= *static_cast<SwFormatField
*>(rEntry
.pAttr
.get());
1590 SwField
* pField
= rFormatField
.GetField();
1592 if (!RefToVar(pField
, rEntry
))
1595 if( IsFootnoteEdnBkmField(rFormatField
, nBkmNo
) )
1597 ::sw::mark::IMark
const * const pMark
= pDoc
->getIDocumentMarkAccess()->getAllMarksBegin()[nBkmNo
];
1599 const SwPosition
& rBkMrkPos
= pMark
->GetMarkPos();
1601 SwTextNode
* pText
= rBkMrkPos
.nNode
.GetNode().GetTextNode();
1602 if( pText
&& rBkMrkPos
.nContent
.GetIndex() )
1604 SwTextAttr
* const pFootnote
= pText
->GetTextAttrForCharAt(
1605 rBkMrkPos
.nContent
.GetIndex()-1, RES_TXTATR_FTN
);
1608 sal_uInt16 nRefNo
= static_cast<SwTextFootnote
*>(pFootnote
)->GetSeqRefNo();
1610 static_cast<SwGetRefField
*>(pField
)->SetSeqNo( nRefNo
);
1612 if( pFootnote
->GetFootnote().IsEndNote() )
1613 static_cast<SwGetRefField
*>(pField
)->SetSubType(REF_ENDNOTE
);
1619 pDoc
->getIDocumentContentOperations().InsertPoolItem(aPaM
, *rEntry
.pAttr
);
1620 MoveAttrs(*aPaM
.GetPoint());
1624 SwFltEndStack::SetAttrInDoc(rTmpPos
, rEntry
);
1627 case RES_FLTR_BOOKMARK
:
1628 OSL_ENSURE(false, "EndStck used with non field, not what we want");
1629 SwFltEndStack::SetAttrInDoc(rTmpPos
, rEntry
);
1635 For styles we will do our tabstop arithmetic in word style and adjust them to
1636 writer style after all the styles have been finished and the dust settles as
1637 to what affects what.
1639 For explicit attributes we turn the adjusted writer tabstops back into 0 based
1640 word indexes and we'll turn them back into writer indexes when setting them
1641 into the document. If explicit left indent exist which affects them, then this
1642 is handled when the explicit left indent is set into the document
1644 void SwWW8ImplReader::Read_Tab(sal_uInt16
, const sal_uInt8
* pData
, short nLen
)
1648 m_xCtrlStck
->SetAttr(*m_pPaM
->GetPoint(), RES_PARATR_TABSTOP
);
1652 sal_uInt8 nDel
= (nLen
> 0) ? pData
[0] : 0;
1653 const sal_uInt8
* pDel
= pData
+ 1; // Del - Array
1655 sal_uInt8 nIns
= (nLen
> nDel
*2+1) ? pData
[nDel
*2+1] : 0;
1656 const sal_uInt8
* pIns
= pData
+ 2*nDel
+ 2; // Ins - Array
1658 short nRequiredLength
= 2 + 2*nDel
+ 2*nIns
+ 1*nIns
;
1659 if (nRequiredLength
> nLen
)
1661 // would require more data than available to describe!
1662 // discard invalid record
1667 WW8_TBD
const * pTyp
= reinterpret_cast<WW8_TBD
const *>(pData
+ 2*nDel
+ 2*nIns
+ 2); // Type Array
1669 std::shared_ptr
<SvxTabStopItem
> aAttr(std::make_shared
<SvxTabStopItem
>(0, 0, SvxTabAdjust::Default
, RES_PARATR_TABSTOP
));
1671 const SwFormat
* pSty
= nullptr;
1672 sal_uInt16 nTabBase
;
1673 if (m_pCurrentColl
&& m_nCurrentColl
< m_vColl
.size()) // StyleDef
1675 nTabBase
= m_vColl
[m_nCurrentColl
].m_nBase
;
1676 if (nTabBase
< m_vColl
.size()) // Based On
1677 pSty
= m_vColl
[nTabBase
].m_pFormat
;
1681 nTabBase
= m_nCurrentColl
;
1682 if (m_nCurrentColl
< m_vColl
.size())
1683 pSty
= m_vColl
[m_nCurrentColl
].m_pFormat
;
1684 //TODO: figure out else here
1687 bool bFound
= false;
1688 std::unordered_set
<size_t> aLoopWatch
;
1689 while (pSty
&& !bFound
)
1691 const SfxPoolItem
* pTabs
;
1692 bFound
= pSty
->GetAttrSet().GetItemState(RES_PARATR_TABSTOP
, false,
1693 &pTabs
) == SfxItemState::SET
;
1696 aAttr
.reset(static_cast<SvxTabStopItem
*>(pTabs
->Clone()));
1700 sal_uInt16 nOldTabBase
= nTabBase
;
1701 // If based on another
1702 if (nTabBase
< m_vColl
.size())
1703 nTabBase
= m_vColl
[nTabBase
].m_nBase
;
1706 nTabBase
< m_vColl
.size() &&
1707 nOldTabBase
!= nTabBase
&&
1708 nTabBase
!= ww::stiNil
1711 // #i61789: Stop searching when next style is the same as the
1712 // current one (prevent loop)
1713 aLoopWatch
.insert(reinterpret_cast<size_t>(pSty
));
1714 if (nTabBase
< m_vColl
.size())
1715 pSty
= m_vColl
[nTabBase
].m_pFormat
;
1716 //TODO figure out the else branch
1718 if (aLoopWatch
.find(reinterpret_cast<size_t>(pSty
)) !=
1723 pSty
= nullptr; // Give up on the search
1727 SvxTabStop aTabStop
;
1728 for (short i
=0; i
< nDel
; ++i
)
1730 sal_uInt16 nPos
= aAttr
->GetPos(SVBT16ToUInt16(pDel
+ i
*2));
1731 if( nPos
!= SVX_TAB_NOTFOUND
)
1732 aAttr
->Remove( nPos
);
1735 for (short i
=0; i
< nIns
; ++i
)
1737 short nPos
= SVBT16ToUInt16(pIns
+ i
*2);
1738 aTabStop
.GetTabPos() = nPos
;
1739 switch( pTyp
[i
].aBits1
& 0x7 ) // pTyp[i].jc
1742 aTabStop
.GetAdjustment() = SvxTabAdjust::Left
;
1745 aTabStop
.GetAdjustment() = SvxTabAdjust::Center
;
1748 aTabStop
.GetAdjustment() = SvxTabAdjust::Right
;
1751 aTabStop
.GetAdjustment() = SvxTabAdjust::Decimal
;
1754 continue; // Ignore Bar
1757 switch( pTyp
[i
].aBits1
>> 3 & 0x7 )
1760 aTabStop
.GetFill() = ' ';
1763 aTabStop
.GetFill() = '.';
1766 aTabStop
.GetFill() = '-';
1770 aTabStop
.GetFill() = '_';
1774 sal_uInt16 nPos2
= aAttr
->GetPos( nPos
);
1775 if (nPos2
!= SVX_TAB_NOTFOUND
)
1776 aAttr
->Remove(nPos2
); // Or else Insert() refuses
1777 aAttr
->Insert(aTabStop
);
1784 // Here we have a tab definition which inserts no extra tabs, or deletes
1785 // no existing tabs. An older version of writer is probably the creator
1786 // of the document :-( . So if we are importing a style we can just
1787 // ignore it. But if we are importing into text we cannot as during
1788 // text SwWW8ImplReader::Read_Tab is called at the begin and end of
1789 // the range the attrib affects, and ignoring it would upset the
1791 if (!m_pCurrentColl
) // not importing into a style
1793 SvxTabStopItem aOrig
= pSty
?
1794 ItemGet
<SvxTabStopItem
>(*pSty
, RES_PARATR_TABSTOP
) :
1795 DefaultItemGet
<SvxTabStopItem
>(m_rDoc
, RES_PARATR_TABSTOP
);
1804 void SwWW8ImplReader::ImportDop()
1806 // correct the LastPrinted date in DocumentProperties
1807 uno::Reference
<document::XDocumentPropertiesSupplier
> xDPS(
1808 m_pDocShell
->GetModel(), uno::UNO_QUERY_THROW
);
1809 uno::Reference
<document::XDocumentProperties
> xDocuProps(
1810 xDPS
->getDocumentProperties());
1811 OSL_ENSURE(xDocuProps
.is(), "DocumentProperties is null");
1812 if (xDocuProps
.is())
1814 DateTime
aLastPrinted(
1815 msfilter::util::DTTM2DateTime(m_xWDop
->dttmLastPrint
));
1816 ::util::DateTime uDT
= aLastPrinted
.GetUNODateTime();
1817 xDocuProps
->setPrintDate(uDT
);
1820 // COMPATIBILITY FLAGS START
1822 // #i78951# - remember the unknown compatibility options
1823 // so as to export them out
1824 m_rDoc
.getIDocumentSettingAccess().Setn32DummyCompatibilityOptions1(m_xWDop
->GetCompatibilityOptions());
1825 m_rDoc
.getIDocumentSettingAccess().Setn32DummyCompatibilityOptions2(m_xWDop
->GetCompatibilityOptions2());
1827 // The distance between two paragraphs is the sum of the bottom distance of
1828 // the first paragraph and the top distance of the second one
1829 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::PARA_SPACE_MAX
, m_xWDop
->fDontUseHTMLAutoSpacing
);
1830 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::PARA_SPACE_MAX_AT_PAGES
, true );
1831 // move tabs on alignment
1832 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::TAB_COMPAT
, true);
1833 // #i24363# tab stops relative to indent
1834 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::TABS_RELATIVE_TO_INDENT
, false);
1836 m_rDoc
.getIDocumentSettingAccess().set(
1837 DocumentSettingId::APPLY_PARAGRAPH_MARK_FORMAT_TO_NUMBERING
, true);
1839 // Import Default Tabs
1840 long nDefTabSiz
= m_xWDop
->dxaTab
;
1841 if( nDefTabSiz
< 56 )
1844 // We want exactly one DefaultTab
1845 SvxTabStopItem
aNewTab( 1, sal_uInt16(nDefTabSiz
), SvxTabAdjust::Default
, RES_PARATR_TABSTOP
);
1846 const_cast<SvxTabStop
&>(aNewTab
[0]).GetAdjustment() = SvxTabAdjust::Default
;
1848 m_rDoc
.GetAttrPool().SetPoolDefaultItem( aNewTab
);
1850 // Import zoom factor
1851 if (m_xWDop
->wScaleSaved
)
1854 sal_Int16 nZoomType
;
1855 switch (m_xWDop
->zkSaved
) {
1856 case 1: nZoomType
= sal_Int16(SvxZoomType::WHOLEPAGE
); break;
1857 case 2: nZoomType
= sal_Int16(SvxZoomType::PAGEWIDTH
); break;
1858 case 3: nZoomType
= sal_Int16(SvxZoomType::OPTIMAL
); break;
1859 default: nZoomType
= sal_Int16(SvxZoomType::PERCENT
); break;
1861 uno::Sequence
<beans::PropertyValue
> aViewProps( comphelper::InitPropertySequence({
1862 { "ZoomFactor", uno::Any(sal_Int16(m_xWDop
->wScaleSaved
)) },
1863 { "VisibleBottom", uno::Any(sal_Int32(0)) },
1864 { "ZoomType", uno::Any(nZoomType
) }
1867 uno::Reference
< uno::XComponentContext
> xComponentContext(comphelper::getProcessComponentContext());
1868 uno::Reference
<container::XIndexContainer
> xBox
= document::IndexedPropertyValues::create(xComponentContext
);
1869 xBox
->insertByIndex(sal_Int32(0), uno::makeAny(aViewProps
));
1870 uno::Reference
<document::XViewDataSupplier
> xViewDataSupplier(m_pDocShell
->GetModel(), uno::UNO_QUERY
);
1871 xViewDataSupplier
->setViewData(xBox
);
1874 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::USE_VIRTUAL_DEVICE
, !m_xWDop
->fUsePrinterMetrics
);
1875 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::USE_HIRES_VIRTUAL_DEVICE
, true);
1876 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::ADD_FLY_OFFSETS
, true );
1877 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::ADD_EXT_LEADING
, !m_xWDop
->fNoLeading
);
1878 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::OLD_NUMBERING
, false);
1879 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING
, false); // #i47448#
1880 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::DO_NOT_JUSTIFY_LINES_WITH_MANUAL_BREAK
, !m_xWDop
->fExpShRtn
); // #i49277#, #i56856#
1881 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::DO_NOT_RESET_PARA_ATTRS_FOR_NUM_FONT
, false); // #i53199#
1882 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::OLD_LINE_SPACING
, false);
1884 // #i25901# - set new compatibility option
1885 // 'Add paragraph and table spacing at bottom of table cells'
1886 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::ADD_PARA_SPACING_TO_TABLE_CELLS
, true);
1888 // #i11860# - set new compatibility option
1889 // 'Use former object positioning' to <false>
1890 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::USE_FORMER_OBJECT_POS
, false);
1892 // #i27767# - set new compatibility option
1893 // 'Consider Wrapping mode when positioning object' to <true>
1894 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION
, true);
1896 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::USE_FORMER_TEXT_WRAPPING
, false); // #i13832#, #i24135#
1898 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::TABLE_ROW_KEEP
, true); //SetTableRowKeep( true );
1900 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::IGNORE_TABS_AND_BLANKS_FOR_LINE_CALCULATION
, true); // #i3952#
1902 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::INVERT_BORDER_SPACING
, true);
1903 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::COLLAPSE_EMPTY_CELL_PARA
, true);
1904 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::TAB_OVERFLOW
, true);
1905 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::UNBREAKABLE_NUMBERINGS
, true);
1906 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::CLIPPED_PICTURES
, true);
1907 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::TAB_OVER_MARGIN
, true);
1908 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::SURROUND_TEXT_WRAP_SMALL
, true);
1909 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::PROP_LINE_SPACING_SHRINKS_FIRST_LINE
, true);
1911 // COMPATIBILITY FLAGS END
1913 // Import magic doptypography information, if its there
1914 if (m_xWwFib
->m_nFib
> 105)
1915 ImportDopTypography(m_xWDop
->doptypography
);
1917 // disable form design mode to be able to use imported controls directly
1918 // #i31239# always disable form design mode, not only in protected docs
1919 uno::Reference
<beans::XPropertySet
> xDocProps(m_pDocShell
->GetModel(), uno::UNO_QUERY
);
1922 uno::Reference
<beans::XPropertySetInfo
> xInfo
= xDocProps
->getPropertySetInfo();
1925 if (xInfo
->hasPropertyByName("ApplyFormDesignMode"))
1926 xDocProps
->setPropertyValue("ApplyFormDesignMode", css::uno::makeAny(false));
1930 // Still allow editing of form fields.
1931 if (!m_xWDop
->fProtEnabled
)
1932 m_pDocShell
->SetModifyPasswordHash(m_xWDop
->lKeyProtDoc
);
1933 else if ( xDocProps
.is() )
1935 comphelper::SequenceAsHashMap
aGrabBag(xDocProps
->getPropertyValue("InteropGrabBag"));
1936 aGrabBag
["FormPasswordHash"] <<= m_xWDop
->lKeyProtDoc
;
1937 xDocProps
->setPropertyValue("InteropGrabBag", uno::Any(aGrabBag
.getAsConstPropertyValueList()));
1940 const SvtFilterOptions
& rOpt
= SvtFilterOptions::Get();
1941 if (rOpt
.IsUseEnhancedFields())
1942 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::PROTECT_FORM
, m_xWDop
->fProtEnabled
);
1945 void SwWW8ImplReader::ImportDopTypography(const WW8DopTypography
&rTypo
)
1947 switch (rTypo
.m_iLevelOfKinsoku
)
1951 i18n::ForbiddenCharacters
aForbidden(rTypo
.m_rgxchFPunct
,
1952 rTypo
.m_rgxchLPunct
);
1953 m_rDoc
.getIDocumentSettingAccess().setForbiddenCharacters(rTypo
.GetConvertedLang(),
1955 // Obviously cannot set the standard level 1 for japanese, so
1956 // bail out now while we can.
1957 if (rTypo
.GetConvertedLang() == LANGUAGE_JAPANESE
)
1966 This MS hack means that level 2 of japanese is not in operation, so we put
1967 in what we know are the MS defaults, there is a complementary reverse
1968 hack in the writer. Its our default as well, but we can set it anyway
1969 as a flag for later.
1971 if (!rTypo
.m_reserved2
)
1973 i18n::ForbiddenCharacters
aForbidden(WW8DopTypography::GetJapanNotBeginLevel1(),
1974 WW8DopTypography::GetJapanNotEndLevel1());
1975 m_rDoc
.getIDocumentSettingAccess().setForbiddenCharacters(LANGUAGE_JAPANESE
,aForbidden
);
1978 m_rDoc
.getIDocumentSettingAccess().set(DocumentSettingId::KERN_ASIAN_PUNCTUATION
, bool(rTypo
.m_fKerningPunct
));
1979 m_rDoc
.getIDocumentSettingAccess().setCharacterCompressionType(static_cast<CharCompressType
>(rTypo
.m_iJustification
));
1983 * Footnotes and Endnotes
1985 WW8ReaderSave::WW8ReaderSave(SwWW8ImplReader
* pRdr
,WW8_CP nStartCp
) :
1986 maTmpPos(*pRdr
->m_pPaM
->GetPoint()),
1987 mxOldStck(std::move(pRdr
->m_xCtrlStck
)),
1988 mxOldAnchorStck(std::move(pRdr
->m_xAnchorStck
)),
1989 mxOldRedlines(std::move(pRdr
->m_xRedlineStack
)),
1990 mxOldPlcxMan(pRdr
->m_xPlcxMan
),
1991 mpWFlyPara(std::move(pRdr
->m_xWFlyPara
)),
1992 mpSFlyPara(std::move(pRdr
->m_xSFlyPara
)),
1993 mpPreviousNumPaM(pRdr
->m_pPreviousNumPaM
),
1994 mpPrevNumRule(pRdr
->m_pPrevNumRule
),
1995 mxTableDesc(std::move(pRdr
->m_xTableDesc
)),
1996 mnInTable(pRdr
->m_nInTable
),
1997 mnCurrentColl(pRdr
->m_nCurrentColl
),
1998 mcSymbol(pRdr
->m_cSymbol
),
1999 mbIgnoreText(pRdr
->m_bIgnoreText
),
2000 mbSymbol(pRdr
->m_bSymbol
),
2001 mbHdFtFootnoteEdn(pRdr
->m_bHdFtFootnoteEdn
),
2002 mbTxbxFlySection(pRdr
->m_bTxbxFlySection
),
2003 mbAnl(pRdr
->m_bAnl
),
2004 mbInHyperlink(pRdr
->m_bInHyperlink
),
2005 mbPgSecBreak(pRdr
->m_bPgSecBreak
),
2006 mbWasParaEnd(pRdr
->m_bWasParaEnd
),
2007 mbHasBorder(pRdr
->m_bHasBorder
),
2008 mbFirstPara(pRdr
->m_bFirstPara
)
2010 pRdr
->m_bSymbol
= false;
2011 pRdr
->m_bHdFtFootnoteEdn
= true;
2012 pRdr
->m_bTxbxFlySection
= pRdr
->m_bAnl
= pRdr
->m_bPgSecBreak
= pRdr
->m_bWasParaEnd
2013 = pRdr
->m_bHasBorder
= false;
2014 pRdr
->m_bFirstPara
= true;
2015 pRdr
->m_nInTable
= 0;
2016 pRdr
->m_pPreviousNumPaM
= nullptr;
2017 pRdr
->m_pPrevNumRule
= nullptr;
2018 pRdr
->m_nCurrentColl
= 0;
2020 pRdr
->m_xCtrlStck
.reset(new SwWW8FltControlStack(&pRdr
->m_rDoc
, pRdr
->m_nFieldFlags
,
2023 pRdr
->m_xRedlineStack
.reset(new sw::util::RedlineStack(pRdr
->m_rDoc
));
2025 pRdr
->m_xAnchorStck
.reset(new SwWW8FltAnchorStack(&pRdr
->m_rDoc
, pRdr
->m_nFieldFlags
));
2027 // Save the attribute manager: we need this as the newly created PLCFx Manager
2028 // access the same FKPs as the old one and their Start-End position changes.
2029 if (pRdr
->m_xPlcxMan
)
2030 pRdr
->m_xPlcxMan
->SaveAllPLCFx(maPLCFxSave
);
2034 pRdr
->m_xPlcxMan
.reset(new WW8PLCFMan(pRdr
->m_xSBase
.get(),
2035 mxOldPlcxMan
->GetManType(), nStartCp
));
2038 maOldApos
.push_back(false);
2039 maOldApos
.swap(pRdr
->m_aApos
);
2040 maOldFieldStack
.swap(pRdr
->m_aFieldStack
);
2043 void WW8ReaderSave::Restore( SwWW8ImplReader
* pRdr
)
2045 pRdr
->m_xWFlyPara
= std::move(mpWFlyPara
);
2046 pRdr
->m_xSFlyPara
= std::move(mpSFlyPara
);
2047 pRdr
->m_pPreviousNumPaM
= mpPreviousNumPaM
;
2048 pRdr
->m_pPrevNumRule
= mpPrevNumRule
;
2049 pRdr
->m_xTableDesc
= std::move(mxTableDesc
);
2050 pRdr
->m_cSymbol
= mcSymbol
;
2051 pRdr
->m_bSymbol
= mbSymbol
;
2052 pRdr
->m_bIgnoreText
= mbIgnoreText
;
2053 pRdr
->m_bHdFtFootnoteEdn
= mbHdFtFootnoteEdn
;
2054 pRdr
->m_bTxbxFlySection
= mbTxbxFlySection
;
2055 pRdr
->m_nInTable
= mnInTable
;
2056 pRdr
->m_bAnl
= mbAnl
;
2057 pRdr
->m_bInHyperlink
= mbInHyperlink
;
2058 pRdr
->m_bWasParaEnd
= mbWasParaEnd
;
2059 pRdr
->m_bPgSecBreak
= mbPgSecBreak
;
2060 pRdr
->m_nCurrentColl
= mnCurrentColl
;
2061 pRdr
->m_bHasBorder
= mbHasBorder
;
2062 pRdr
->m_bFirstPara
= mbFirstPara
;
2064 // Close all attributes as attributes could be created that extend the Fly
2065 pRdr
->DeleteCtrlStack();
2066 pRdr
->m_xCtrlStck
= std::move(mxOldStck
);
2068 pRdr
->m_xRedlineStack
->closeall(*pRdr
->m_pPaM
->GetPoint());
2069 pRdr
->m_aFrameRedlines
.emplace(std::move(pRdr
->m_xRedlineStack
));
2070 pRdr
->m_xRedlineStack
= std::move(mxOldRedlines
);
2072 pRdr
->DeleteAnchorStack();
2073 pRdr
->m_xAnchorStck
= std::move(mxOldAnchorStck
);
2075 *pRdr
->m_pPaM
->GetPoint() = maTmpPos
;
2077 if (mxOldPlcxMan
!= pRdr
->m_xPlcxMan
)
2078 pRdr
->m_xPlcxMan
= mxOldPlcxMan
;
2079 if (pRdr
->m_xPlcxMan
)
2080 pRdr
->m_xPlcxMan
->RestoreAllPLCFx(maPLCFxSave
);
2081 pRdr
->m_aApos
.swap(maOldApos
);
2082 pRdr
->m_aFieldStack
.swap(maOldFieldStack
);
2085 void SwWW8ImplReader::Read_HdFtFootnoteText( const SwNodeIndex
* pSttIdx
,
2086 WW8_CP nStartCp
, WW8_CP nLen
, ManTypes nType
)
2088 if (nStartCp
< 0 || nLen
< 0)
2091 // Saves Flags (amongst other things) and resets them
2092 WW8ReaderSave
aSave( this );
2094 m_pPaM
->GetPoint()->nNode
= pSttIdx
->GetIndex() + 1;
2095 m_pPaM
->GetPoint()->nContent
.Assign( m_pPaM
->GetContentNode(), 0 );
2097 // Read Text for Header, Footer or Footnote
2098 ReadText( nStartCp
, nLen
, nType
); // Ignore Sepx when doing so
2099 aSave
.Restore( this );
2103 * Use authornames, if not available fall back to initials.
2105 long SwWW8ImplReader::Read_And(WW8PLCFManResult
* pRes
)
2107 WW8PLCFx_SubDoc
* pSD
= m_xPlcxMan
->GetAtn();
2111 const void* pData
= pSD
->GetData();
2119 const WW67_ATRD
* pDescri
= static_cast<const WW67_ATRD
*>(pData
);
2120 const OUString
* pA
= GetAnnotationAuthor(SVBT16ToUInt16(pDescri
->ibst
));
2125 const sal_uInt8 nLen
= std::min
<sal_uInt8
>(pDescri
->xstUsrInitl
[0],
2126 SAL_N_ELEMENTS(pDescri
->xstUsrInitl
)-1);
2127 sAuthor
= OUString(pDescri
->xstUsrInitl
+ 1, nLen
, RTL_TEXTENCODING_MS_1252
);
2132 const WW8_ATRD
* pDescri
= static_cast<const WW8_ATRD
*>(pData
);
2134 const sal_uInt16 nLen
= std::min
<sal_uInt16
>(SVBT16ToUInt16(pDescri
->xstUsrInitl
[0]),
2135 SAL_N_ELEMENTS(pDescri
->xstUsrInitl
)-1);
2136 OUStringBuffer aBuf
;
2137 aBuf
.setLength(nLen
);
2138 for(sal_uInt16 nIdx
= 1; nIdx
<= nLen
; ++nIdx
)
2139 aBuf
[nIdx
-1] = SVBT16ToUInt16(pDescri
->xstUsrInitl
[nIdx
]);
2140 sInitials
= aBuf
.makeStringAndClear();
2143 if (const OUString
* pA
= GetAnnotationAuthor(SVBT16ToUInt16(pDescri
->ibst
)))
2146 sAuthor
= sInitials
;
2149 sal_uInt32 nDateTime
= 0;
2151 if (sal_uInt8
* pExtended
= m_xPlcxMan
->GetExtendedAtrds()) // Word < 2002 has no date data for comments
2153 sal_uLong nIndex
= pSD
->GetIdx() & 0xFFFF; // Index is (stupidly) multiplexed for WW8PLCFx_SubDocs
2154 if (m_xWwFib
->m_lcbAtrdExtra
/18 > nIndex
)
2155 nDateTime
= SVBT32ToUInt32(*reinterpret_cast<SVBT32
*>(pExtended
+(nIndex
*18)));
2158 DateTime aDate
= msfilter::util::DTTM2DateTime(nDateTime
);
2161 std::unique_ptr
<OutlinerParaObject
> pOutliner
= ImportAsOutliner( sText
, pRes
->nCp2OrIdx
,
2162 pRes
->nCp2OrIdx
+ pRes
->nMemLen
, MAN_AND
);
2164 m_pFormatOfJustInsertedApo
= nullptr;
2165 SwPostItField
aPostIt(
2166 static_cast<SwPostItFieldType
*>(m_rDoc
.getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::Postit
)), sAuthor
,
2167 sText
, sInitials
, OUString(), aDate
);
2168 aPostIt
.SetTextObject(std::move(pOutliner
));
2170 SwPaM
aEnd(*m_pPaM
->End(), *m_pPaM
->End());
2171 m_xCtrlStck
->NewAttr(*aEnd
.GetPoint(), SvxCharHiddenItem(false, RES_CHRATR_HIDDEN
));
2172 m_rDoc
.getIDocumentContentOperations().InsertPoolItem(aEnd
, SwFormatField(aPostIt
));
2173 m_xCtrlStck
->SetAttr(*aEnd
.GetPoint(), RES_CHRATR_HIDDEN
);
2174 // If this is a range, make sure that it ends after the just inserted character, not before it.
2175 m_xReffedStck
->MoveAttrs(*aEnd
.GetPoint(), SwFltControlStack::MoveAttrsMode::POSTIT_INSERTED
);
2180 void SwWW8ImplReader::Read_HdFtTextAsHackedFrame(WW8_CP nStart
, WW8_CP nLen
,
2181 SwFrameFormat
const &rHdFtFormat
, sal_uInt16 nPageWidth
)
2183 const SwNodeIndex
* pSttIdx
= rHdFtFormat
.GetContent().GetContentIdx();
2184 OSL_ENSURE(pSttIdx
, "impossible");
2188 SwPosition
aTmpPos(*m_pPaM
->GetPoint());
2190 m_pPaM
->GetPoint()->nNode
= pSttIdx
->GetIndex() + 1;
2191 m_pPaM
->GetPoint()->nContent
.Assign(m_pPaM
->GetContentNode(), 0);
2193 // tdf#122425: Explicitly remove borders and spacing
2194 SfxItemSet
aFlySet(m_rDoc
.GetAttrPool(), svl::Items
<RES_FRMATR_BEGIN
, RES_FRMATR_END
- 1>{});
2195 Reader::ResetFrameFormatAttrs(aFlySet
);
2197 SwFlyFrameFormat
* pFrame
2198 = m_rDoc
.MakeFlySection(RndStdIds::FLY_AT_PARA
, m_pPaM
->GetPoint(), &aFlySet
);
2200 SwFormatAnchor
aAnch( pFrame
->GetAnchor() );
2201 aAnch
.SetType( RndStdIds::FLY_AT_PARA
);
2202 pFrame
->SetFormatAttr( aAnch
);
2203 SwFormatFrameSize
aSz(ATT_MIN_SIZE
, nPageWidth
, MINLAY
);
2204 SwFrameSize eFrameSize
= ATT_MIN_SIZE
;
2205 if( eFrameSize
!= aSz
.GetWidthSizeType() )
2206 aSz
.SetWidthSizeType( eFrameSize
);
2207 pFrame
->SetFormatAttr(aSz
);
2208 pFrame
->SetFormatAttr(SwFormatSurround(css::text::WrapTextMode_THROUGH
));
2209 pFrame
->SetFormatAttr(SwFormatHoriOrient(0, text::HoriOrientation::LEFT
)); //iFOO
2211 // #i43427# - send frame for header/footer into background.
2212 pFrame
->SetFormatAttr( SvxOpaqueItem( RES_OPAQUE
, false ) );
2213 SdrObject
* pFrameObj
= CreateContactObject( pFrame
);
2214 OSL_ENSURE( pFrameObj
,
2215 "<SwWW8ImplReader::Read_HdFtTextAsHackedFrame(..)> - missing SdrObject instance" );
2218 pFrameObj
->SetOrdNum( 0 );
2220 MoveInsideFly(pFrame
);
2222 const SwNodeIndex
* pHackIdx
= pFrame
->GetContent().GetContentIdx();
2224 Read_HdFtFootnoteText(pHackIdx
, nStart
, nLen
- 1, MAN_HDFT
);
2226 MoveOutsideFly(pFrame
, aTmpPos
);
2229 void SwWW8ImplReader::Read_HdFtText(WW8_CP nStart
, WW8_CP nLen
, SwFrameFormat
const * pHdFtFormat
)
2231 const SwNodeIndex
* pSttIdx
= pHdFtFormat
->GetContent().GetContentIdx();
2235 SwPosition
aTmpPos( *m_pPaM
->GetPoint() ); // Remember old cursor position
2237 Read_HdFtFootnoteText(pSttIdx
, nStart
, nLen
- 1, MAN_HDFT
);
2239 *m_pPaM
->GetPoint() = aTmpPos
;
2242 bool SwWW8ImplReader::isValid_HdFt_CP(WW8_CP nHeaderCP
) const
2244 // Each CP of Plcfhdd MUST be less than FibRgLw97.ccpHdd
2245 return (nHeaderCP
< m_xWwFib
->m_ccpHdr
&& nHeaderCP
>= 0);
2248 bool SwWW8ImplReader::HasOwnHeaderFooter(sal_uInt8 nWhichItems
, sal_uInt8 grpfIhdt
,
2253 WW8_CP nStart
, nLen
;
2254 sal_uInt8 nNumber
= 5;
2256 for( sal_uInt8 nI
= 0x20; nI
; nI
>>= 1, nNumber
-- )
2258 if (nI
& nWhichItems
)
2262 bOk
= ( m_xHdFt
->GetTextPos(grpfIhdt
, nI
, nStart
, nLen
) && nStart
>= 0 && nLen
>= 2 );
2265 m_xHdFt
->GetTextPosExact( static_cast< short >(nNumber
+ (nSect
+1)*6), nStart
, nLen
);
2266 bOk
= ( 2 <= nLen
) && isValid_HdFt_CP(nStart
);
2277 void SwWW8ImplReader::Read_HdFt(int nSect
, const SwPageDesc
*pPrev
,
2278 const wwSection
&rSection
)
2280 sal_uInt8 grpfIhdt
= rSection
.maSep
.grpfIhdt
;
2281 SwPageDesc
*pPD
= rSection
.mpPage
;
2285 WW8_CP nStart
, nLen
;
2286 sal_uInt8 nNumber
= 5;
2288 // This loops through the 6 flags WW8_{FOOTER,HEADER}_{ODD,EVEN,FIRST}
2289 // corresponding to bit fields in grpfIhdt indicating which
2290 // header/footer(s) are present in this section
2291 for( sal_uInt8 nI
= 0x20; nI
; nI
>>= 1, nNumber
-- )
2297 bOk
= ( m_xHdFt
->GetTextPos(grpfIhdt
, nI
, nStart
, nLen
) && nLen
>= 2 );
2300 m_xHdFt
->GetTextPosExact( static_cast< short >(nNumber
+ (nSect
+1)*6), nStart
, nLen
);
2301 bOk
= ( 2 <= nLen
) && isValid_HdFt_CP(nStart
);
2305 = (nI
& ( WW8_HEADER_EVEN
| WW8_FOOTER_EVEN
)) != 0;
2307 = (nI
& ( WW8_HEADER_FIRST
| WW8_FOOTER_FIRST
)) != 0;
2309 // If we are loading a first-page header/footer which is not
2310 // actually enabled in this section (it still needs to be
2311 // loaded as it may be inherited by a later section)
2312 bool bDisabledFirst
= bUseFirst
&& !rSection
.HasTitlePage();
2315 = (nI
& ( WW8_FOOTER_EVEN
| WW8_FOOTER_ODD
| WW8_FOOTER_FIRST
)) != 0;
2317 SwFrameFormat
& rFormat
= bUseLeft
? pPD
->GetLeft()
2318 : bUseFirst
? pPD
->GetFirstMaster()
2321 SwFrameFormat
* pHdFtFormat
;
2322 // If we have empty first page header and footer.
2323 bool bNoFirst
= !(grpfIhdt
& WW8_HEADER_FIRST
) && !(grpfIhdt
& WW8_FOOTER_FIRST
);
2327 //#i17196# Cannot have left without right
2329 && !pPD
->GetMaster().GetFooter().GetFooterFormat())
2330 pPD
->GetMaster().SetFormatAttr(SwFormatFooter(true));
2332 pPD
->GetLeft().SetFormatAttr(SwFormatFooter(true));
2333 if (bUseFirst
|| (rSection
.maSep
.fTitlePage
&& bNoFirst
))
2334 pPD
->GetFirstMaster().SetFormatAttr(SwFormatFooter(true));
2335 pHdFtFormat
= const_cast<SwFrameFormat
*>(rFormat
.GetFooter().GetFooterFormat());
2340 //#i17196# Cannot have left without right
2342 && !pPD
->GetMaster().GetHeader().GetHeaderFormat())
2343 pPD
->GetMaster().SetFormatAttr(SwFormatHeader(true));
2345 pPD
->GetLeft().SetFormatAttr(SwFormatHeader(true));
2346 if (bUseFirst
|| (rSection
.maSep
.fTitlePage
&& bNoFirst
))
2347 pPD
->GetFirstMaster().SetFormatAttr(SwFormatHeader(true));
2348 pHdFtFormat
= const_cast<SwFrameFormat
*>(rFormat
.GetHeader().GetHeaderFormat());
2353 bool bHackRequired
= false;
2354 if (m_bIsHeader
&& rSection
.IsFixedHeightHeader())
2355 bHackRequired
= true;
2356 else if (m_bIsFooter
&& rSection
.IsFixedHeightFooter())
2357 bHackRequired
= true;
2361 Read_HdFtTextAsHackedFrame(nStart
, nLen
, *pHdFtFormat
,
2362 static_cast< sal_uInt16
>(rSection
.GetTextAreaWidth()) );
2365 Read_HdFtText(nStart
, nLen
, pHdFtFormat
);
2368 CopyPageDescHdFt(pPrev
, pPD
, nI
);
2370 m_bIsHeader
= m_bIsFooter
= false;
2376 bool wwSectionManager::SectionIsProtected(const wwSection
&rSection
) const
2378 return ( mrReader
.m_xWDop
->fProtEnabled
&& !rSection
.IsNotProtected() );
2381 void wwSectionManager::SetHdFt(wwSection
const &rSection
, int nSect
,
2382 const wwSection
*pPrevious
)
2384 // Header/Footer not present
2385 if (!rSection
.maSep
.grpfIhdt
)
2388 OSL_ENSURE(rSection
.mpPage
, "makes no sense to call with a main page");
2389 if (rSection
.mpPage
)
2391 mrReader
.Read_HdFt(nSect
, pPrevious
? pPrevious
->mpPage
: nullptr,
2395 // Header/Footer - Update Index
2396 // So that the index is still valid later on
2397 if (mrReader
.m_xHdFt
)
2398 mrReader
.m_xHdFt
->UpdateIndex(rSection
.maSep
.grpfIhdt
);
2402 void SwWW8ImplReader::AppendTextNode(SwPosition
& rPos
)
2404 SwTextNode
* pText
= m_pPaM
->GetNode().GetTextNode();
2406 const SwNumRule
* pRule
= nullptr;
2408 if (pText
!= nullptr)
2409 pRule
= sw::util::GetNumRuleFromTextNode(*pText
);
2412 pRule
&& !m_xWDop
->fDontUseHTMLAutoSpacing
&&
2413 (m_bParaAutoBefore
|| m_bParaAutoAfter
)
2416 // If after spacing is set to auto, set the after space to 0
2417 if (m_bParaAutoAfter
)
2418 SetLowerSpacing(*m_pPaM
, 0);
2420 // If the previous textnode had numbering and
2421 // and before spacing is set to auto, set before space to 0
2422 if(m_pPrevNumRule
&& m_bParaAutoBefore
)
2423 SetUpperSpacing(*m_pPaM
, 0);
2425 // If the previous numbering rule was different we need
2426 // to insert a space after the previous paragraph
2427 if((pRule
!= m_pPrevNumRule
) && m_pPreviousNumPaM
)
2428 SetLowerSpacing(*m_pPreviousNumPaM
, GetParagraphAutoSpace(m_xWDop
->fDontUseHTMLAutoSpacing
));
2430 // cache current paragraph
2431 if(m_pPreviousNumPaM
)
2433 delete m_pPreviousNumPaM
;
2434 m_pPreviousNumPaM
= nullptr;
2437 m_pPreviousNumPaM
= new SwPaM(*m_pPaM
, m_pPaM
);
2438 m_pPrevNumRule
= pRule
;
2440 else if(!pRule
&& m_pPreviousNumPaM
)
2442 // If the previous paragraph has numbering but the current one does not
2443 // we need to add a space after the previous paragraph
2444 SetLowerSpacing(*m_pPreviousNumPaM
, GetParagraphAutoSpace(m_xWDop
->fDontUseHTMLAutoSpacing
));
2445 delete m_pPreviousNumPaM
;
2446 m_pPreviousNumPaM
= nullptr;
2447 m_pPrevNumRule
= nullptr;
2451 // clear paragraph cache
2452 if(m_pPreviousNumPaM
)
2454 delete m_pPreviousNumPaM
;
2455 m_pPreviousNumPaM
= nullptr;
2457 m_pPrevNumRule
= pRule
;
2460 // If this is the first paragraph in the document and
2461 // Auto-spacing before paragraph is set,
2462 // set the upper spacing value to 0
2463 if(m_bParaAutoBefore
&& m_bFirstPara
&& !m_xWDop
->fDontUseHTMLAutoSpacing
)
2464 SetUpperSpacing(*m_pPaM
, 0);
2466 m_bFirstPara
= false;
2468 m_rDoc
.getIDocumentContentOperations().AppendTextNode(rPos
);
2470 // We can flush all anchored graphics at the end of a paragraph.
2471 m_xAnchorStck
->Flush();
2474 bool SwWW8ImplReader::SetSpacing(SwPaM
&rMyPam
, int nSpace
, bool bIsUpper
)
2477 const SwPosition
* pSpacingPos
= rMyPam
.GetPoint();
2479 const SvxULSpaceItem
* pULSpaceItem
= m_xCtrlStck
->GetFormatAttr(*pSpacingPos
, RES_UL_SPACE
);
2481 if(pULSpaceItem
!= nullptr)
2483 SvxULSpaceItem
aUL(*pULSpaceItem
);
2486 aUL
.SetUpper( static_cast< sal_uInt16
>(nSpace
) );
2488 aUL
.SetLower( static_cast< sal_uInt16
>(nSpace
) );
2490 const sal_Int32 nEnd
= pSpacingPos
->nContent
.GetIndex();
2491 rMyPam
.GetPoint()->nContent
.Assign(rMyPam
.GetContentNode(), 0);
2492 m_xCtrlStck
->NewAttr(*pSpacingPos
, aUL
);
2493 rMyPam
.GetPoint()->nContent
.Assign(rMyPam
.GetContentNode(), nEnd
);
2494 m_xCtrlStck
->SetAttr(*pSpacingPos
, RES_UL_SPACE
);
2500 bool SwWW8ImplReader::SetLowerSpacing(SwPaM
&rMyPam
, int nSpace
)
2502 return SetSpacing(rMyPam
, nSpace
, false);
2505 bool SwWW8ImplReader::SetUpperSpacing(SwPaM
&rMyPam
, int nSpace
)
2507 return SetSpacing(rMyPam
, nSpace
, true);
2510 sal_uInt16
SwWW8ImplReader::TabRowSprm(int nLevel
) const
2514 return nLevel
? 0x244C : 0x2417;
2517 void SwWW8ImplReader::EndSpecial()
2521 StopAllAnl(); // -> bAnl = false
2523 while(m_aApos
.size() > 1)
2528 if (m_aApos
[m_nInTable
])
2535 OSL_ENSURE(!m_nInTable
, "unclosed table!");
2538 bool SwWW8ImplReader::FloatingTableConversion(WW8PLCFx_Cp_FKP
* pPap
)
2540 // This is ww8 version of the code deciding if the table needs to be
2541 // in a floating frame.
2542 // For OOXML code, see SectionPropertyMap::FloatingTableConversion in
2543 // writerfilter/source/dmapper/PropertyMap.cxx
2544 // The two should do ~same, so if you make changes here, please check
2545 // that the other is in sync.
2547 // Note that this is just a list of heuristics till sw core can have a
2548 // table that is floating and can span over multiple pages at the same
2551 bool bResult
= true;
2553 SprmResult aRes
= pPap
->HasSprm(NS_sprm::sprmTDefTable
);
2554 if (nullptr != aRes
.pSprm
)
2557 WW8TabBandDesc aDesc
;
2558 aDesc
.ReadDef(false, aRes
.pSprm
, aRes
.nRemainingData
);
2559 int nTextAreaWidth
= m_aSectionManager
.GetTextAreaWidth();
2560 int nTableWidth
= aDesc
.nCenter
[aDesc
.nWwCols
] - aDesc
.nCenter
[0];
2562 // It seems Word has a limit here, so that in case the table width is quite
2563 // close to the text area width, then it won't perform a wrapping, even in
2564 // case the content (e.g. an empty paragraph) would fit. The magic constant
2565 // here represents this limit.
2566 const int nMagicNumber
= 469;
2568 // If the table is wider than the text area, then don't create a fly
2569 // for the table: no wrapping will be performed anyway, but multi-page
2570 // tables will be broken.
2571 if ((nTableWidth
+ nMagicNumber
) < nTextAreaWidth
)
2574 // If there are columns, do create a fly, as the flow of the columns
2575 // would otherwise restrict the table.
2576 if (!bResult
&& (m_aSectionManager
.CurrentSectionColCount() >= 2))
2582 WW8PLCFxSave1 aSave
;
2584 if (SearchTableEnd(pPap
))
2586 // Table is considered to be imported into a fly frame and we
2587 // know where the end of the table is.
2589 WW8_FC nFc
= m_xSBase
->WW8Cp2Fc(pPap
->Where(), &bIsUnicode
);
2590 sal_uInt64 nPos
= m_pStrm
->Tell();
2592 sal_uInt16 nUChar
= 0;
2594 m_pStrm
->ReadUInt16(nUChar
);
2597 sal_uInt8 nChar
= 0;
2598 m_pStrm
->ReadUChar(nChar
);
2601 m_pStrm
->Seek(nPos
);
2603 // The pap after the table starts with a page break, so
2604 // there will be no wrapping around the float-table.
2605 // Request no fly in this case, so the table can properly
2606 // be a multi-page one if necessary.
2609 pPap
->Restore(aSave
);
2615 bool SwWW8ImplReader::ProcessSpecial(bool &rbReSync
, WW8_CP nStartCp
)
2623 OSL_ENSURE(m_nInTable
>= 0,"nInTable < 0!");
2626 bool bTableRowEnd
= (m_xPlcxMan
->HasParaSprm(m_bVer67
? 25 : 0x2417).pSprm
!= nullptr);
2628 // Unfortunately, for every paragraph we need to check first whether
2629 // they contain a sprm 29 (0x261B), which starts an APO.
2630 // All other sprms then refer to that APO and not to the normal text
2632 // The same holds true for a Table (sprm 24 (0x2416)) and Anls (sprm 13).
2634 // WW: Table in APO is possible (Both Start-Ends occur at the same time)
2635 // WW: APO in Table not possible
2637 // This mean that of a Table is the content of an APO, the APO start needs
2638 // to be edited first, so that the Table remains in the APO and not the
2639 // other way around.
2640 // At the End, however, we need to edit the Table End first as the APO
2641 // must end after that Table (or else we never find the APO End).
2643 // The same holds true for Fly / Anl, Tab / Anl, Fly / Tab / Anl.
2645 // If the Table is within an APO the TabRowEnd Area misses the
2647 // To not end the APO there, we do not call ProcessApo
2649 // KHZ: When there is a table inside the Apo the Apo-flags are also
2650 // missing for the 2nd, 3rd... paragraphs of each cell.
2652 // 1st look for in-table flag, for 2000+ there is a subtable flag to
2653 // be considered, the sprm 6649 gives the level of the table
2654 sal_uInt8 nCellLevel
= 0;
2657 nCellLevel
= int(nullptr != m_xPlcxMan
->HasParaSprm(24).pSprm
);
2660 nCellLevel
= int(nullptr != m_xPlcxMan
->HasParaSprm(0x2416).pSprm
);
2662 nCellLevel
= int(nullptr != m_xPlcxMan
->HasParaSprm(0x244B).pSprm
);
2666 WW8_TablePos
*pTabPos
=nullptr;
2667 WW8_TablePos aTabPos
;
2668 if(nCellLevel
&& !m_bVer67
)
2670 WW8PLCFxSave1 aSave
;
2671 m_xPlcxMan
->GetPap()->Save( aSave
);
2673 WW8PLCFx_Cp_FKP
* pPap
= m_xPlcxMan
->GetPapPLCF();
2674 WW8_CP nMyStartCp
=nStartCp
;
2676 SprmResult aLevel
= m_xPlcxMan
->HasParaSprm(0x6649);
2677 if (aLevel
.pSprm
&& aLevel
.nRemainingData
>= 1)
2678 nCellLevel
= *aLevel
.pSprm
;
2680 bool bHasRowEnd
= SearchRowEnd(pPap
, nMyStartCp
, (m_nInTable
<nCellLevel
?m_nInTable
:nCellLevel
-1));
2682 // Bad Table, remain unchanged in level, e.g. #i19667#
2684 nCellLevel
= static_cast< sal_uInt8
>(m_nInTable
);
2686 if (bHasRowEnd
&& ParseTabPos(&aTabPos
,pPap
))
2689 m_xPlcxMan
->GetPap()->Restore( aSave
);
2692 // Then look if we are in an Apo
2694 ApoTestResults aApo
= TestApo(nCellLevel
, bTableRowEnd
, pTabPos
);
2696 // Look to see if we are in a Table, but Table in foot/end note not allowed
2697 bool bStartTab
= (m_nInTable
< nCellLevel
) && !m_bFootnoteEdn
;
2699 bool bStopTab
= m_bWasTabRowEnd
&& (m_nInTable
> nCellLevel
) && !m_bFootnoteEdn
;
2701 m_bWasTabRowEnd
= false; // must be deactivated right here to prevent next
2702 // WW8TabDesc::TableCellEnd() from making nonsense
2704 if (m_nInTable
&& !bTableRowEnd
&& !bStopTab
&& (m_nInTable
== nCellLevel
&& aApo
.HasStartStop()))
2705 bStopTab
= bStartTab
= true; // Required to stop and start table
2707 // Test for Anl (Numbering) and process all events in the right order
2708 if( m_bAnl
&& !bTableRowEnd
)
2710 SprmResult aSprm13
= m_xPlcxMan
->HasParaSprm(13);
2711 const sal_uInt8
* pSprm13
= aSprm13
.pSprm
;
2712 if (pSprm13
&& aSprm13
.nRemainingData
>= 1)
2713 { // Still Anl left?
2714 sal_uInt8 nT
= static_cast< sal_uInt8
>(GetNumType( *pSprm13
));
2715 if( ( nT
!= WW8_Pause
&& nT
!= m_nWwNumType
) // Anl change
2716 || aApo
.HasStartStop() // Forced Anl end
2717 || bStopTab
|| bStartTab
)
2719 StopAnlToRestart(nT
); // Anl-Restart (= change) over sprms
2723 NextAnlLine( pSprm13
); // Next Anl Line
2727 { // Regular Anl end
2728 StopAllAnl(); // Actual end
2740 m_aApos
[m_nInTable
] = false;
2743 if (aApo
.mbStartApo
)
2745 m_aApos
[m_nInTable
] = StartApo(aApo
, pTabPos
);
2746 // We need an ReSync after StartApo
2747 // (actually only if the Apo extends past a FKP border)
2752 WW8PLCFxSave1 aSave
;
2753 m_xPlcxMan
->GetPap()->Save( aSave
);
2755 // Numbering for cell borders causes a crash -> no Anls in Tables
2759 if(m_nInTable
< nCellLevel
)
2761 if (StartTable(nStartCp
))
2765 m_aApos
.push_back(false);
2768 if(m_nInTable
>= nCellLevel
)
2770 // We need an ReSync after StartTable
2771 // (actually only if the Apo extends past a FKP border)
2773 m_xPlcxMan
->GetPap()->Restore( aSave
);
2776 } while (!m_bFootnoteEdn
&& (m_nInTable
< nCellLevel
));
2777 return bTableRowEnd
;
2780 rtl_TextEncoding
SwWW8ImplReader::GetCharSetFromLanguage()
2784 The (default) character set used for a run of text is the default
2785 character set for the version of Word that last saved the document.
2787 This is a bit tentative, more might be required if the concept is correct.
2788 When later version of word write older 6/95 documents the charset is
2789 correctly set in the character runs involved, so it's hard to reproduce
2790 documents that require this to be sure of the process involved.
2792 const SvxLanguageItem
*pLang
= static_cast<const SvxLanguageItem
*>(GetFormatAttr(RES_CHRATR_LANGUAGE
));
2793 LanguageType eLang
= pLang
? pLang
->GetLanguage() : LANGUAGE_SYSTEM
;
2794 css::lang::Locale
aLocale(LanguageTag::convertToLocale(eLang
));
2795 return msfilter::util::getBestTextEncodingFromLocale(aLocale
);
2798 rtl_TextEncoding
SwWW8ImplReader::GetCJKCharSetFromLanguage()
2802 The (default) character set used for a run of text is the default
2803 character set for the version of Word that last saved the document.
2805 This is a bit tentative, more might be required if the concept is correct.
2806 When later version of word write older 6/95 documents the charset is
2807 correctly set in the character runs involved, so it's hard to reproduce
2808 documents that require this to be sure of the process involved.
2810 const SvxLanguageItem
*pLang
= static_cast<const SvxLanguageItem
*>(GetFormatAttr(RES_CHRATR_CJK_LANGUAGE
));
2811 LanguageType eLang
= pLang
? pLang
->GetLanguage() : LANGUAGE_SYSTEM
;
2812 css::lang::Locale
aLocale(LanguageTag::convertToLocale(eLang
));
2813 return msfilter::util::getBestTextEncodingFromLocale(aLocale
);
2816 rtl_TextEncoding
SwWW8ImplReader::GetCurrentCharSet()
2820 If the hard charset is set use it, if not see if there is an open
2821 character run that has set the charset, if not then fallback to the
2822 current underlying paragraph style.
2824 rtl_TextEncoding eSrcCharSet
= m_eHardCharSet
;
2825 if (eSrcCharSet
== RTL_TEXTENCODING_DONTKNOW
)
2828 eSrcCharSet
= GetCharSetFromLanguage();
2829 else if (!m_aFontSrcCharSets
.empty())
2830 eSrcCharSet
= m_aFontSrcCharSets
.top();
2831 if ((eSrcCharSet
== RTL_TEXTENCODING_DONTKNOW
) && m_nCharFormat
>= 0 && static_cast<size_t>(m_nCharFormat
) < m_vColl
.size() )
2832 eSrcCharSet
= m_vColl
[m_nCharFormat
].GetCharSet();
2833 if ((eSrcCharSet
== RTL_TEXTENCODING_DONTKNOW
) && StyleExists(m_nCurrentColl
) && m_nCurrentColl
< m_vColl
.size())
2834 eSrcCharSet
= m_vColl
[m_nCurrentColl
].GetCharSet();
2835 if (eSrcCharSet
== RTL_TEXTENCODING_DONTKNOW
)
2836 eSrcCharSet
= GetCharSetFromLanguage();
2841 //Takashi Ono for CJK
2842 rtl_TextEncoding
SwWW8ImplReader::GetCurrentCJKCharSet()
2846 If the hard charset is set use it, if not see if there is an open
2847 character run that has set the charset, if not then fallback to the
2848 current underlying paragraph style.
2850 rtl_TextEncoding eSrcCharSet
= m_eHardCharSet
;
2851 if (eSrcCharSet
== RTL_TEXTENCODING_DONTKNOW
)
2853 if (!m_aFontSrcCJKCharSets
.empty())
2854 eSrcCharSet
= m_aFontSrcCJKCharSets
.top();
2855 if ((eSrcCharSet
== RTL_TEXTENCODING_DONTKNOW
) && m_nCharFormat
>= 0 && static_cast<size_t>(m_nCharFormat
) < m_vColl
.size() )
2856 eSrcCharSet
= m_vColl
[m_nCharFormat
].GetCJKCharSet();
2857 if (eSrcCharSet
== RTL_TEXTENCODING_DONTKNOW
&& StyleExists(m_nCurrentColl
) && m_nCurrentColl
< m_vColl
.size())
2858 eSrcCharSet
= m_vColl
[m_nCurrentColl
].GetCJKCharSet();
2859 if (eSrcCharSet
== RTL_TEXTENCODING_DONTKNOW
)
2860 eSrcCharSet
= GetCJKCharSetFromLanguage();
2865 void SwWW8ImplReader::PostProcessAttrs()
2867 if (m_pPostProcessAttrsInfo
!= nullptr)
2869 SfxItemIter
aIter(m_pPostProcessAttrsInfo
->mItemSet
);
2871 const SfxPoolItem
* pItem
= aIter
.GetCurItem();
2872 if (pItem
!= nullptr)
2876 m_xCtrlStck
->NewAttr(*m_pPostProcessAttrsInfo
->mPaM
.GetPoint(),
2878 m_xCtrlStck
->SetAttr(*m_pPostProcessAttrsInfo
->mPaM
.GetMark(),
2881 while (!aIter
.IsAtEnd() && nullptr != (pItem
= aIter
.NextItem()));
2884 m_pPostProcessAttrsInfo
.reset();
2890 It appears that some documents that are in a baltic 8 bit encoding which has
2891 some undefined characters can have use made of those characters, in which
2892 case they default to CP1252. If not then it's perhaps that the font encoding
2893 is only in use for 6/7 and for 8+ if we are in 8bit mode then the encoding
2896 So an encoding converter that on an undefined character attempts to
2897 convert from 1252 on the undefined character
2899 static std::size_t Custom8BitToUnicode(rtl_TextToUnicodeConverter hConverter
,
2900 sal_Char
const *pIn
, std::size_t nInLen
, sal_Unicode
*pOut
, std::size_t nOutLen
)
2902 const sal_uInt32 nFlags
=
2903 RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
|
2904 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
|
2905 RTL_TEXTTOUNICODE_FLAGS_INVALID_IGNORE
|
2906 RTL_TEXTTOUNICODE_FLAGS_FLUSH
;
2908 const sal_uInt32 nFlags2
=
2909 RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_IGNORE
|
2910 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_IGNORE
|
2911 RTL_TEXTTOUNICODE_FLAGS_INVALID_IGNORE
|
2912 RTL_TEXTTOUNICODE_FLAGS_FLUSH
;
2914 std::size_t nDestChars
=0;
2915 std::size_t nConverted
=0;
2919 sal_uInt32 nInfo
= 0;
2920 sal_Size nThisConverted
=0;
2922 nDestChars
+= rtl_convertTextToUnicode(hConverter
, nullptr,
2923 pIn
+nConverted
, nInLen
-nConverted
,
2924 pOut
+nDestChars
, nOutLen
-nDestChars
,
2925 nFlags
, &nInfo
, &nThisConverted
);
2927 OSL_ENSURE(nInfo
== 0, "A character conversion failed!");
2929 nConverted
+= nThisConverted
;
2932 nInfo
& RTL_TEXTTOUNICODE_INFO_UNDEFINED
||
2933 nInfo
& RTL_TEXTTOUNICODE_INFO_MBUNDEFINED
2936 sal_Size nOtherConverted
;
2937 rtl_TextToUnicodeConverter hCP1252Converter
=
2938 rtl_createTextToUnicodeConverter(RTL_TEXTENCODING_MS_1252
);
2939 nDestChars
+= rtl_convertTextToUnicode(hCP1252Converter
, nullptr,
2941 pOut
+nDestChars
, nOutLen
-nDestChars
,
2942 nFlags2
, &nInfo
, &nOtherConverted
);
2943 rtl_destroyTextToUnicodeConverter(hCP1252Converter
);
2946 } while (nConverted
< nInLen
);
2951 bool SwWW8ImplReader::LangUsesHindiNumbers(LanguageType nLang
)
2953 bool bResult
= false;
2955 switch (static_cast<sal_uInt16
>(nLang
))
2957 case 0x1401: // Arabic(Algeria)
2958 case 0x3c01: // Arabic(Bahrain)
2959 case 0xc01: // Arabic(Egypt)
2960 case 0x801: // Arabic(Iraq)
2961 case 0x2c01: // Arabic (Jordan)
2962 case 0x3401: // Arabic(Kuwait)
2963 case 0x3001: // Arabic(Lebanon)
2964 case 0x1001: // Arabic(Libya)
2965 case 0x1801: // Arabic(Morocco)
2966 case 0x2001: // Arabic(Oman)
2967 case 0x4001: // Arabic(Qatar)
2968 case 0x401: // Arabic(Saudi Arabia)
2969 case 0x2801: // Arabic(Syria)
2970 case 0x1c01: // Arabic(Tunisia)
2971 case 0x3801: // Arabic(U.A.E)
2972 case 0x2401: // Arabic(Yemen)
2982 sal_Unicode
SwWW8ImplReader::TranslateToHindiNumbers(sal_Unicode nChar
)
2984 if (nChar
>= 0x0030 && nChar
<= 0x0039)
2985 return nChar
+ 0x0630;
2992 OUString
makeOUString(rtl_uString
*pStr
, sal_Int32 nAllocLen
)
2994 //if read len was in or around that of allocated len, just reuse pStr
2995 if (nAllocLen
< pStr
->length
+ 256)
2996 return OUString(pStr
, SAL_NO_ACQUIRE
);
2997 //otherwise copy the shorter used section to release extra mem
2998 OUString
sRet(pStr
->buffer
, pStr
->length
);
2999 rtl_uString_release(pStr
);
3005 * Return value: true for non special chars
3007 bool SwWW8ImplReader::ReadPlainChars(WW8_CP
& rPos
, sal_Int32 nEnd
, sal_Int32 nCpOfs
)
3009 sal_Int32 nRequestedStrLen
= nEnd
- rPos
;
3011 OSL_ENSURE(nRequestedStrLen
, "String is 0");
3012 if (nRequestedStrLen
<= 0)
3015 sal_Int32 nRequestedPos
= m_xSBase
->WW8Cp2Fc(nCpOfs
+rPos
, &m_bIsUnicode
);
3016 bool bValidPos
= checkSeek(*m_pStrm
, nRequestedPos
);
3017 OSL_ENSURE(bValidPos
, "Document claimed to have more text than available");
3020 // Swallow missing range, e.g. #i95550#
3021 rPos
+=nRequestedStrLen
;
3025 std::size_t nAvailableStrLen
= m_pStrm
->remainingSize() / (m_bIsUnicode
? 2 : 1);
3026 OSL_ENSURE(nAvailableStrLen
, "Document claimed to have more text than available");
3027 if (!nAvailableStrLen
)
3029 // Swallow missing range, e.g. #i95550#
3030 rPos
+=nRequestedStrLen
;
3034 sal_Int32 nValidStrLen
= std::min
<std::size_t>(nRequestedStrLen
, nAvailableStrLen
);
3036 // Reset Unicode flag and correct FilePos if needed.
3037 // Note: Seek is not expensive, as we're checking inline whether or not
3038 // the correct FilePos has already been reached.
3039 const sal_Int32 nStrLen
= std::min(nValidStrLen
, SAL_MAX_INT32
-1);
3041 rtl_TextEncoding eSrcCharSet
= m_bVer67
? GetCurrentCharSet() :
3042 RTL_TEXTENCODING_MS_1252
;
3043 if (m_bVer67
&& eSrcCharSet
== RTL_TEXTENCODING_MS_932
)
3048 Older documents exported as word 95 that use unicode aware fonts will
3049 have the charset of those fonts set to RTL_TEXTENCODING_MS_932 on
3050 export as the conversion from RTL_TEXTENCODING_UNICODE. This is a serious
3053 We will try and use a fallback encoding if the conversion from
3054 RTL_TEXTENCODING_MS_932 fails, but you can get unlucky and get a document
3055 which isn't really in RTL_TEXTENCODING_MS_932 but parts of it form
3056 valid RTL_TEXTENCODING_MS_932 by chance :-(
3058 We're not the only ones that struggle with this: Here's the help from
3059 MSOffice 2003 on the topic:
3062 Earlier versions of Microsoft Word were sometimes used in conjunction with
3063 third-party language-processing add-in programs designed to support Chinese or
3064 Korean on English versions of Microsoft Windows. Use of these add-ins sometimes
3065 results in incorrect text display in more recent versions of Word.
3067 However, you can set options to convert these documents so that text is
3068 displayed correctly. On the Tools menu, click Options, and then click the
3069 General tab. In the English Word 6.0/95 documents list, select Contain Asian
3070 text (to have Word interpret the text as Asian code page data, regardless of
3071 its font) or Automatically detect Asian text (to have Word attempt to determine
3072 which parts of the text are meant to be Asian).
3075 What we can try here is to ignore a RTL_TEXTENCODING_MS_932 codepage if
3076 the language is not Japanese
3079 const SfxPoolItem
* pItem
= GetFormatAttr(RES_CHRATR_CJK_LANGUAGE
);
3080 if (pItem
!= nullptr && LANGUAGE_JAPANESE
!= static_cast<const SvxLanguageItem
*>(pItem
)->GetLanguage())
3082 SAL_WARN("sw.ww8", "discarding word95 RTL_TEXTENCODING_MS_932 encoding");
3083 eSrcCharSet
= GetCharSetFromLanguage();
3086 const rtl_TextEncoding eSrcCJKCharSet
= m_bVer67
? GetCurrentCJKCharSet() :
3087 RTL_TEXTENCODING_MS_1252
;
3089 // allocate unicode string data
3090 rtl_uString
*pStr
= rtl_uString_alloc(nStrLen
);
3091 sal_Unicode
* pBuffer
= pStr
->buffer
;
3092 sal_Unicode
* pWork
= pBuffer
;
3094 std::unique_ptr
<sal_Char
[]> p8Bits
;
3096 rtl_TextToUnicodeConverter hConverter
= nullptr;
3097 if (!m_bIsUnicode
|| m_bVer67
)
3098 hConverter
= rtl_createTextToUnicodeConverter(eSrcCharSet
);
3101 p8Bits
.reset( new sal_Char
[nStrLen
] );
3103 // read the stream data
3104 sal_uInt8 nBCode
= 0;
3107 LanguageType nCTLLang
= LANGUAGE_SYSTEM
;
3108 const SfxPoolItem
* pItem
= GetFormatAttr(RES_CHRATR_CTL_LANGUAGE
);
3109 if (pItem
!= nullptr)
3110 nCTLLang
= static_cast<const SvxLanguageItem
*>(pItem
)->GetLanguage();
3113 for (nL2
= 0; nL2
< nStrLen
; ++nL2
)
3116 m_pStrm
->ReadUInt16( nUCode
); // unicode --> read 2 bytes
3119 m_pStrm
->ReadUChar( nBCode
); // old code --> read 1 byte
3123 if (m_pStrm
->GetError())
3125 rPos
= WW8_CP_MAX
-10; // -> eof or other error
3130 if ((32 > nUCode
) || (0xa0 == nUCode
))
3132 m_pStrm
->SeekRel( m_bIsUnicode
? -2 : -1 );
3133 break; // Special character < 32, == 0xa0 found
3142 if (nUCode
>= 0x3000) //0x8000 ?
3145 aTest
[0] = static_cast< sal_Char
>((nUCode
& 0xFF00) >> 8);
3146 aTest
[1] = static_cast< sal_Char
>(nUCode
& 0x00FF);
3147 OUString
aTemp(aTest
, 2, eSrcCJKCharSet
);
3148 OSL_ENSURE(aTemp
.getLength() == 1, "so much for that theory");
3149 *pWork
++ = aTemp
[0];
3153 sal_Char cTest
= static_cast< sal_Char
>(nUCode
& 0x00FF);
3154 pWork
+= Custom8BitToUnicode(hConverter
, &cTest
, 1, pWork
, 1);
3159 p8Bits
[nL2
] = nBCode
;
3164 const sal_Int32 nEndUsed
= !m_bIsUnicode
3165 ? Custom8BitToUnicode(hConverter
, p8Bits
.get(), nL2
, pBuffer
, nStrLen
)
3168 if (m_bRegardHindiDigits
&& m_bBidi
&& LangUsesHindiNumbers(nCTLLang
))
3170 for (sal_Int32 nI
= 0; nI
< nEndUsed
; ++nI
, ++pBuffer
)
3171 *pBuffer
= TranslateToHindiNumbers(*pBuffer
);
3174 pStr
->buffer
[nEndUsed
] = 0;
3175 pStr
->length
= nEndUsed
;
3177 emulateMSWordAddTextToParagraph(makeOUString(pStr
, nStrLen
));
3180 if (!m_aApos
.back()) // a para end in apo doesn't count
3181 m_bWasParaEnd
= false; // No CR
3185 rtl_destroyTextToUnicodeConverter(hConverter
);
3187 rtl_uString_release(pStr
);
3188 return nL2
>= nStrLen
;
3191 #define MSASCII SAL_MAX_INT16
3195 // We want to force weak chars inside 0x0020 to 0x007F to LATIN
3196 sal_Int16
lcl_getScriptType(
3197 const uno::Reference
<i18n::XBreakIterator
>& rBI
,
3198 const OUString
&rString
, sal_Int32 nPos
)
3200 sal_Int16 nScript
= rBI
->getScriptType(rString
, nPos
);
3201 if (nScript
== i18n::ScriptType::WEAK
&& rString
[nPos
] >= 0x0020 && rString
[nPos
] <= 0x007F)
3206 // We want to know about WEAK segments, so endOfScript isn't
3207 // useful, and see lcl_getScriptType anyway
3208 sal_Int32
lcl_endOfScript(
3209 const uno::Reference
<i18n::XBreakIterator
>& rBI
,
3210 const OUString
&rString
, sal_Int32 nPos
, sal_Int16 nScript
)
3212 while (nPos
< rString
.getLength())
3214 sal_Int16 nNewScript
= lcl_getScriptType(rBI
, rString
, nPos
);
3215 if (nScript
!= nNewScript
)
3222 sal_Int32
lcl_getWriterScriptType(
3223 const uno::Reference
<i18n::XBreakIterator
>& rBI
,
3224 const OUString
&rString
, sal_Int32 nPos
)
3226 sal_Int16 nScript
= i18n::ScriptType::WEAK
;
3228 if (rString
.isEmpty())
3233 nScript
= rBI
->getScriptType(rString
, nPos
);
3234 if (nScript
!= i18n::ScriptType::WEAK
)
3242 bool samePitchIgnoreUnknown(FontPitch eA
, FontPitch eB
)
3244 return (eA
== eB
|| eA
== PITCH_DONTKNOW
|| eB
== PITCH_DONTKNOW
);
3247 bool sameFontIgnoringIrrelevantFields(const SvxFontItem
&rA
, const SvxFontItem
&rB
)
3249 // Ignoring CharSet, and ignoring unknown pitch
3250 return rA
.GetFamilyName() == rB
.GetFamilyName() &&
3251 rA
.GetStyleName() == rB
.GetStyleName() &&
3252 rA
.GetFamily() == rB
.GetFamily() &&
3253 samePitchIgnoreUnknown(rA
.GetPitch(), rB
.GetPitch());
3257 // In writer we categorize text into CJK, CTL and "Western" for everything else.
3258 // Microsoft Word basically categorizes text into East Asian, Complex, ASCII,
3259 // NonEastAsian/HighAnsi, with some shared characters and some properties to
3260 // hint as to which way to bias those shared characters.
3262 // That's four categories, we however have three categories. Given that problem
3263 // here we would ideally find out "what would word do" to see what font/language
3264 // word would assign to characters based on the unicode range they fall into and
3265 // hack the word one onto the range we use. However it's unclear what word's
3266 // categorization is. So we don't do that here yet.
3268 // Additional to the categorization, when word encounters weak text for ambiguous
3269 // chars it uses idcthint to indicate which way to bias. We don't have an idcthint
3270 // feature in writer.
3272 // So what we currently do here then is to split our text into non-weak/weak
3273 // sections and uses word's idcthint to determine what font it would use and
3274 // force that on for the segment. Following what we *do* know about word's
3275 // categorization, we know that the range 0x0020 and 0x007F is sprmCRgFtc0 in
3276 // word, something we map to LATIN, so we consider all weak chars in that range
3277 // to auto-bias to LATIN.
3279 // See https://bugs.libreoffice.org/show_bug.cgi?id=34319 for an example
3280 void SwWW8ImplReader::emulateMSWordAddTextToParagraph(const OUString
& rAddString
)
3282 if (rAddString
.isEmpty())
3285 uno::Reference
<i18n::XBreakIterator
> xBI(g_pBreakIt
->GetBreakIter());
3288 sal_Int16 nScript
= lcl_getScriptType(xBI
, rAddString
, 0);
3289 sal_Int32 nLen
= rAddString
.getLength();
3291 OUString sParagraphText
;
3292 const SwContentNode
*pCntNd
= m_pPaM
->GetContentNode();
3293 const SwTextNode
* pNd
= pCntNd
? pCntNd
->GetTextNode() : nullptr;
3295 sParagraphText
= pNd
->GetText();
3296 sal_Int32 nParaOffset
= sParagraphText
.getLength();
3297 sParagraphText
= sParagraphText
+ rAddString
;
3302 sal_Int32 nEnd
= lcl_endOfScript(xBI
, rAddString
, nPos
, nScript
);
3306 OUString
sChunk(rAddString
.copy(nPos
, nEnd
-nPos
));
3307 const sal_uInt16 aIds
[] = {RES_CHRATR_FONT
, RES_CHRATR_CJK_FONT
, RES_CHRATR_CTL_FONT
};
3308 const SvxFontItem
*pOverriddenItems
[] = {nullptr, nullptr, nullptr};
3309 bool aForced
[] = {false, false, false};
3311 int nLclIdctHint
= 0xFF;
3312 if (nScript
== i18n::ScriptType::WEAK
)
3314 const SfxInt16Item
*pIdctHint
= static_cast<const SfxInt16Item
*>(GetFormatAttr(RES_CHRATR_IDCTHINT
));
3315 nLclIdctHint
= pIdctHint
->GetValue();
3317 else if (nScript
== MSASCII
) // Force weak chars in ascii range to use LATIN font
3320 sal_uInt16 nForceFromFontId
= 0;
3321 if (nLclIdctHint
!= 0xFF)
3323 switch (nLclIdctHint
)
3326 nForceFromFontId
= RES_CHRATR_FONT
;
3329 nForceFromFontId
= RES_CHRATR_CJK_FONT
;
3332 nForceFromFontId
= RES_CHRATR_CTL_FONT
;
3339 if (nForceFromFontId
!= 0)
3341 // Now we know that word would use the nForceFromFontId font for this range
3342 // Try and determine what script writer would assign this range to
3344 sal_Int32 nWriterScript
= lcl_getWriterScriptType(xBI
, sParagraphText
,
3345 nPos
+ nParaOffset
);
3347 bool bWriterWillUseSameFontAsWordAutomatically
= false;
3349 if (nWriterScript
!= i18n::ScriptType::WEAK
)
3352 (nWriterScript
== i18n::ScriptType::ASIAN
&& nForceFromFontId
== RES_CHRATR_CJK_FONT
) ||
3353 (nWriterScript
== i18n::ScriptType::COMPLEX
&& nForceFromFontId
== RES_CHRATR_CTL_FONT
) ||
3354 (nWriterScript
== i18n::ScriptType::LATIN
&& nForceFromFontId
== RES_CHRATR_FONT
)
3357 bWriterWillUseSameFontAsWordAutomatically
= true;
3361 const SvxFontItem
*pSourceFont
= static_cast<const SvxFontItem
*>(GetFormatAttr(nForceFromFontId
));
3362 sal_uInt16 nDestId
= aIds
[nWriterScript
-1];
3363 const SvxFontItem
*pDestFont
= static_cast<const SvxFontItem
*>(GetFormatAttr(nDestId
));
3364 bWriterWillUseSameFontAsWordAutomatically
= sameFontIgnoringIrrelevantFields(*pSourceFont
, *pDestFont
);
3368 // Writer won't use the same font as word, so force the issue
3369 if (!bWriterWillUseSameFontAsWordAutomatically
)
3371 const SvxFontItem
*pSourceFont
= static_cast<const SvxFontItem
*>(GetFormatAttr(nForceFromFontId
));
3373 for (size_t i
= 0; i
< SAL_N_ELEMENTS(aIds
); ++i
)
3375 const SvxFontItem
*pDestFont
= static_cast<const SvxFontItem
*>(GetFormatAttr(aIds
[i
]));
3376 aForced
[i
] = aIds
[i
] != nForceFromFontId
&& *pSourceFont
!= *pDestFont
;
3379 pOverriddenItems
[i
] =
3380 static_cast<const SvxFontItem
*>(m_xCtrlStck
->GetStackAttr(*m_pPaM
->GetPoint(), aIds
[i
]));
3382 SvxFontItem
aForceFont(*pSourceFont
);
3383 aForceFont
.SetWhich(aIds
[i
]);
3384 m_xCtrlStck
->NewAttr(*m_pPaM
->GetPoint(), aForceFont
);
3390 simpleAddTextToParagraph(sChunk
);
3392 for (size_t i
= 0; i
< SAL_N_ELEMENTS(aIds
); ++i
)
3396 m_xCtrlStck
->SetAttr(*m_pPaM
->GetPoint(), aIds
[i
]);
3397 if (pOverriddenItems
[i
])
3398 m_xCtrlStck
->NewAttr(*m_pPaM
->GetPoint(), *(pOverriddenItems
[i
]));
3404 nScript
= lcl_getScriptType(xBI
, rAddString
, nPos
);
3408 void SwWW8ImplReader::simpleAddTextToParagraph(const OUString
& rAddString
)
3410 if (rAddString
.isEmpty())
3413 #if OSL_DEBUG_LEVEL > 1
3414 SAL_INFO("sw.ww8", "<addTextToParagraph>" << rAddString
<< "</addTextToParagraph>");
3417 const SwContentNode
*pCntNd
= m_pPaM
->GetContentNode();
3418 const SwTextNode
* pNd
= pCntNd
? pCntNd
->GetTextNode() : nullptr;
3420 OSL_ENSURE(pNd
, "What the hell, where's my text node");
3425 const sal_Int32 nCharsLeft
= SAL_MAX_INT32
- pNd
->GetText().getLength();
3428 if (rAddString
.getLength() <= nCharsLeft
)
3430 m_rDoc
.getIDocumentContentOperations().InsertString(*m_pPaM
, rAddString
);
3434 m_rDoc
.getIDocumentContentOperations().InsertString(*m_pPaM
, rAddString
.copy(0, nCharsLeft
));
3435 AppendTextNode(*m_pPaM
->GetPoint());
3436 m_rDoc
.getIDocumentContentOperations().InsertString(*m_pPaM
, rAddString
.copy(nCharsLeft
));
3441 AppendTextNode(*m_pPaM
->GetPoint());
3442 m_rDoc
.getIDocumentContentOperations().InsertString(*m_pPaM
, rAddString
);
3445 m_bReadTable
= false;
3449 * Return value: true for para end
3451 bool SwWW8ImplReader::ReadChars(WW8_CP
& rPos
, WW8_CP nNextAttr
, long nTextEnd
,
3454 long nEnd
= ( nNextAttr
< nTextEnd
) ? nNextAttr
: nTextEnd
;
3456 if (m_bSymbol
|| m_bIgnoreText
)
3458 WW8_CP nRequested
= nEnd
- rPos
;
3459 if (m_bSymbol
) // Insert special chars
3461 sal_uInt64 nMaxPossible
= m_pStrm
->remainingSize();
3462 if (static_cast<sal_uInt64
>(nRequested
) > nMaxPossible
)
3464 SAL_WARN("sw.ww8", "document claims to have more characters, " << nRequested
<< " than remaining, " << nMaxPossible
);
3465 nRequested
= nMaxPossible
;
3468 for (WW8_CP nCh
= 0; nCh
< nRequested
; ++nCh
)
3470 m_rDoc
.getIDocumentContentOperations().InsertString( *m_pPaM
, OUString(m_cSymbol
) );
3472 m_xCtrlStck
->SetAttr( *m_pPaM
->GetPoint(), RES_CHRATR_FONT
);
3473 m_xCtrlStck
->SetAttr( *m_pPaM
->GetPoint(), RES_CHRATR_CJK_FONT
);
3474 m_xCtrlStck
->SetAttr( *m_pPaM
->GetPoint(), RES_CHRATR_CTL_FONT
);
3476 m_pStrm
->SeekRel(nRequested
);
3477 rPos
= nEnd
; // Ignore until attribute end
3483 if (ReadPlainChars(rPos
, nEnd
, nCpOfs
))
3484 return false; // Done
3486 bool bStartLine
= ReadChar(rPos
, nCpOfs
);
3488 if (m_bPgSecBreak
|| bStartLine
|| rPos
== nEnd
) // CR or Done
3495 bool SwWW8ImplReader::HandlePageBreakChar()
3497 bool bParaEndAdded
= false;
3498 // #i1909# section/page breaks should not occur in tables, word
3499 // itself ignores them in this case.
3503 SwTextNode
* pTemp
= m_pPaM
->GetNode().GetTextNode();
3504 if (pTemp
&& pTemp
->GetText().isEmpty()
3505 && (m_bFirstPara
|| m_bFirstParaOfPage
))
3508 AppendTextNode(*m_pPaM
->GetPoint());
3509 pTemp
->SetAttr(*GetDfltAttr(RES_PARATR_NUMRULE
));
3512 m_bPgSecBreak
= true;
3513 m_xCtrlStck
->KillUnlockedAttrs(*m_pPaM
->GetPoint());
3515 If it's a 0x0c without a paragraph end before it, act like a
3516 paragraph end, but nevertheless, numbering (and perhaps other
3517 similar constructs) do not exist on the para.
3519 if (!m_bWasParaEnd
&& IsTemp
)
3521 bParaEndAdded
= true;
3522 if (0 >= m_pPaM
->GetPoint()->nContent
.GetIndex())
3524 if (SwTextNode
* pTextNode
= m_pPaM
->GetNode().GetTextNode())
3527 *GetDfltAttr(RES_PARATR_NUMRULE
));
3532 return bParaEndAdded
;
3535 bool SwWW8ImplReader::ReadChar(long nPosCp
, long nCpOfs
)
3537 bool bNewParaEnd
= false;
3538 // Reset Unicode flag and correct FilePos if needed.
3539 // Note: Seek is not expensive, as we're checking inline whether or not
3540 // the correct FilePos has already been reached.
3541 std::size_t nRequestedPos
= m_xSBase
->WW8Cp2Fc(nCpOfs
+nPosCp
, &m_bIsUnicode
);
3542 if (!checkSeek(*m_pStrm
, nRequestedPos
))
3545 sal_uInt8
nBCode(0);
3546 sal_uInt16
nWCharVal(0);
3548 m_pStrm
->ReadUInt16( nWCharVal
); // unicode --> read 2 bytes
3551 m_pStrm
-> ReadUChar( nBCode
); // old code --> read 1 byte
3555 sal_Unicode cInsert
= '\x0';
3556 bool bParaMark
= false;
3558 if ( 0xc != nWCharVal
)
3559 m_bFirstParaOfPage
= false;
3566 SwPageNumberField
aField(
3567 static_cast<SwPageNumberFieldType
*>(m_rDoc
.getIDocumentFieldsAccess().GetSysFieldType(
3568 SwFieldIds::PageNumber
)), PG_RANDOM
, SVX_NUM_ARABIC
);
3569 m_rDoc
.getIDocumentContentOperations().InsertPoolItem(*m_pPaM
, SwFormatField(aField
));
3573 // if there is only one column word treats a column break like a pagebreak.
3574 if (m_aSectionManager
.CurrentSectionColCount() < 2)
3575 bParaMark
= HandlePageBreakChar();
3576 else if (!m_nInTable
)
3578 // Always insert a txtnode for a column break, e.g. ##
3579 SwContentNode
*pCntNd
=m_pPaM
->GetContentNode();
3580 if (pCntNd
!=nullptr && pCntNd
->Len()>0) // if par is empty not break is needed
3581 AppendTextNode(*m_pPaM
->GetPoint());
3582 m_rDoc
.getIDocumentContentOperations().InsertPoolItem(*m_pPaM
, SvxFormatBreakItem(SvxBreak::ColumnBefore
, RES_BREAK
));
3588 WW8PLCFxDesc
* pPap
= m_xPlcxMan
->GetPap();
3589 //The last paragraph of each cell is terminated by a special
3590 //paragraph mark called a cell mark. Following the cell mark
3591 //that ends the last cell of a table row, the table row is
3592 //terminated by a special paragraph mark called a row mark
3594 //So the 0x7 should be right at the end of the previous
3595 //range to be a real cell-end.
3596 if (pPap
->nOrigStartPos
== nPosCp
+1 ||
3597 pPap
->nOrigStartPos
== WW8_CP_MAX
)
3599 TabCellEnd(); // Table cell/row end
3606 if( !m_bSpec
) // "Satellite"
3607 cInsert
= u
'\x00a4';
3610 if( !m_bSpec
) // "Para End" char
3611 cInsert
= u
'\x00b5';
3612 //TODO: should this be U+00B6 PILCROW SIGN rather than
3613 // U+00B5 MICRO SIGN?
3616 if( !m_bSpec
) // Juristenparagraph
3618 cp_set::iterator aItr
= m_aTOXEndCps
.find(static_cast<WW8_CP
>(nPosCp
));
3619 if (aItr
== m_aTOXEndCps
.end())
3620 cInsert
= u
'\x00a7';
3622 m_aTOXEndCps
.erase(aItr
);
3626 cInsert
= '\x9'; // Tab
3629 cInsert
= '\xa'; // Hard NewLine
3632 bParaMark
= HandlePageBreakChar();
3634 case 0x1e: // Non-breaking hyphen
3635 m_rDoc
.getIDocumentContentOperations().InsertString( *m_pPaM
, OUString(CHAR_HARDHYPHEN
) );
3637 case 0x1f: // Non-required hyphens
3638 m_rDoc
.getIDocumentContentOperations().InsertString( *m_pPaM
, OUString(CHAR_SOFTHYPHEN
) );
3640 case 0xa0: // Non-breaking spaces
3641 m_rDoc
.getIDocumentContentOperations().InsertString( *m_pPaM
, OUString(CHAR_HARDBLANK
) );
3645 Current thinking is that if bObj is set then we have a
3646 straightforward "traditional" ole object, otherwise we have a
3647 graphic preview of an associated ole2 object (or a simple
3650 normally in the canvas field, the code is 0x8 0x1.
3651 in a special case, the code is 0x1 0x1, which yields a simple picture
3654 bool bReadObj
= IsInlineEscherHack();
3657 long nCurPos
= m_pStrm
->Tell();
3658 sal_uInt16
nWordCode(0);
3661 m_pStrm
->ReadUInt16( nWordCode
);
3664 sal_uInt8
nByteCode(0);
3665 m_pStrm
->ReadUChar( nByteCode
);
3666 nWordCode
= nByteCode
;
3668 if( nWordCode
== 0x1 )
3670 m_pStrm
->Seek( nCurPos
);
3674 SwFrameFormat
*pResult
= nullptr;
3676 pResult
= ImportOle();
3678 pResult
= ImportGraf();
3680 // If we have a bad 0x1 insert a space instead.
3684 OSL_ENSURE(!m_bObj
&& !m_bEmbeddObj
&& !m_nObjLocFc
,
3685 "WW8: Please report this document, it may have a "
3691 m_bObj
= m_bEmbeddObj
= false;
3699 Read_GrafLayer( nPosCp
);
3702 bNewParaEnd
= bParaMark
= true;
3707 Yes complex, if there is an entry in the undocumented PLCF
3708 which I believe to be a record of cell and row boundaries
3709 see if the magic bit which I believe to mean cell end is
3710 set. I also think btw that the third byte of the 4 byte
3711 value is the level of the cell
3713 WW8PLCFspecial
* pTest
= m_xPlcxMan
->GetMagicTables();
3714 if (pTest
&& pTest
->SeekPosExact(nPosCp
+1+nCpOfs
) &&
3715 pTest
->Where() == nPosCp
+1+nCpOfs
)
3719 sal_uInt32 nData
= pTest
->Get(nPos
, pData
) ? SVBT32ToUInt32(*static_cast<SVBT32
*>(pData
))
3721 if (nData
& 0x2) // Might be how it works
3727 // tdf#106799: We expect TTP marks to be also cell marks,
3728 // but sometimes sprmPFInnerTtp comes without sprmPFInnerTableCell
3729 else if (m_bWasTabCellEnd
|| m_bWasTabRowEnd
)
3736 m_bWasTabCellEnd
= false;
3739 case 0x5: // Annotation reference
3742 case 0x2: // TODO: Auto-Footnote-Number, should be replaced by SwWW8ImplReader::End_Footnote later
3743 if (!m_aFootnoteStack
.empty())
3747 SAL_INFO( "sw.ww8.level2", "<unknownValue val=\"" << nWCharVal
<< "\">" );
3751 if( '\x0' != cInsert
)
3753 OUString
sInsert(cInsert
);
3754 emulateMSWordAddTextToParagraph(sInsert
);
3756 if (!m_aApos
.back()) // a para end in apo doesn't count
3757 m_bWasParaEnd
= bNewParaEnd
;
3761 void SwWW8ImplReader::ProcessCurrentCollChange(WW8PLCFManResult
& rRes
,
3762 bool* pStartAttr
, bool bCallProcessSpecial
)
3764 sal_uInt16 nOldColl
= m_nCurrentColl
;
3765 m_nCurrentColl
= m_xPlcxMan
->GetColl();
3768 if (m_nCurrentColl
>= m_vColl
.size() || !m_vColl
[m_nCurrentColl
].m_pFormat
|| !m_vColl
[m_nCurrentColl
].m_bColl
)
3771 m_bParaAutoBefore
= false;
3772 m_bParaAutoAfter
= false;
3776 m_bParaAutoBefore
= m_vColl
[m_nCurrentColl
].m_bParaAutoBefore
;
3777 m_bParaAutoAfter
= m_vColl
[m_nCurrentColl
].m_bParaAutoAfter
;
3780 if (nOldColl
>= m_vColl
.size())
3781 nOldColl
= 0; // guess! TODO make sure this is what we want
3783 bool bTabRowEnd
= false;
3784 if( pStartAttr
&& bCallProcessSpecial
&& !m_bInHyperlink
)
3787 // Frame/Table/Autonumbering List Level
3788 bTabRowEnd
= ProcessSpecial(bReSync
, rRes
.nCurrentCp
+ m_xPlcxMan
->GetCpOfs());
3790 *pStartAttr
= m_xPlcxMan
->Get( &rRes
); // Get Attribut-Pos again
3793 if (!bTabRowEnd
&& StyleExists(m_nCurrentColl
))
3795 SetTextFormatCollAndListLevel( *m_pPaM
, m_vColl
[ m_nCurrentColl
]);
3796 ChkToggleAttr(m_vColl
[ nOldColl
].m_n81Flags
, m_vColl
[ m_nCurrentColl
].m_n81Flags
);
3797 ChkToggleBiDiAttr(m_vColl
[nOldColl
].m_n81BiDiFlags
,
3798 m_vColl
[m_nCurrentColl
].m_n81BiDiFlags
);
3802 long SwWW8ImplReader::ReadTextAttr(WW8_CP
& rTextPos
, long nTextEnd
, bool& rbStartLine
, int nDepthGuard
)
3804 long nSkipChars
= 0;
3805 WW8PLCFManResult aRes
;
3807 OSL_ENSURE(m_pPaM
->GetNode().GetTextNode(), "Missing txtnode");
3808 bool bStartAttr
= m_xPlcxMan
->Get(&aRes
); // Get Attribute position again
3809 aRes
.nCurrentCp
= rTextPos
; // Current Cp position
3811 bool bNewSection
= (aRes
.nFlags
& MAN_MASK_NEW_SEP
) && !m_bIgnoreText
;
3812 if ( bNewSection
) // New Section
3814 OSL_ENSURE(m_pPaM
->GetNode().GetTextNode(), "Missing txtnode");
3815 // Create PageDesc and fill it
3816 m_aSectionManager
.CreateSep(rTextPos
);
3817 // -> 0xc was a Sectionbreak, but not a Pagebreak;
3818 // Create PageDesc and fill it
3819 m_bPgSecBreak
= false;
3820 OSL_ENSURE(m_pPaM
->GetNode().GetTextNode(), "Missing txtnode");
3823 // New paragraph over Plcx.Fkp.papx
3824 if ( (aRes
.nFlags
& MAN_MASK_NEW_PAP
)|| rbStartLine
)
3826 ProcessCurrentCollChange( aRes
, &bStartAttr
,
3827 MAN_MASK_NEW_PAP
== (aRes
.nFlags
& MAN_MASK_NEW_PAP
) &&
3829 rbStartLine
= false;
3832 // position of last CP that's to be ignored
3835 if( 0 < aRes
.nSprmId
) // Ignore empty Attrs
3837 if( ( eFTN
> aRes
.nSprmId
) || ( 0x0800 <= aRes
.nSprmId
) )
3839 if( bStartAttr
) // WW attributes
3841 if( aRes
.nMemLen
>= 0 )
3842 ImportSprm(aRes
.pMemPos
, aRes
.nMemLen
, aRes
.nSprmId
);
3845 EndSprm( aRes
.nSprmId
); // Switch off Attr
3847 else if( aRes
.nSprmId
< 0x800 ) // Own helper attributes
3851 nSkipChars
= ImportExtSprm(&aRes
);
3853 (aRes
.nSprmId
== eFTN
) || (aRes
.nSprmId
== eEDN
) ||
3854 (aRes
.nSprmId
== eFLD
) || (aRes
.nSprmId
== eAND
)
3857 WW8_CP nMaxLegalSkip
= nTextEnd
- rTextPos
;
3858 // Skip Field/Footnote-/End-Note here
3859 rTextPos
+= std::min
<WW8_CP
>(nSkipChars
, nMaxLegalSkip
);
3860 nSkipPos
= rTextPos
-1;
3864 EndExtSprm( aRes
.nSprmId
);
3868 sal_Int32 nRequestedPos
= m_xSBase
->WW8Cp2Fc(m_xPlcxMan
->GetCpOfs() + rTextPos
, &m_bIsUnicode
);
3869 bool bValidPos
= checkSeek(*m_pStrm
, nRequestedPos
);
3870 SAL_WARN_IF(!bValidPos
, "sw.ww8", "Document claimed to have text at an invalid position, skip attributes for region");
3872 // Find next Attr position (and Skip attributes of field contents if needed)
3873 if (nSkipChars
&& !m_bIgnoreText
)
3874 m_xCtrlStck
->MarkAllAttrsOld();
3875 bool bOldIgnoreText
= m_bIgnoreText
;
3876 m_bIgnoreText
= true;
3877 sal_uInt16 nOldColl
= m_nCurrentColl
;
3878 bool bDoPlcxManPlusPLus
= true;
3882 if( bDoPlcxManPlusPLus
)
3883 m_xPlcxMan
->advance();
3884 nNext
= bValidPos
? m_xPlcxMan
->Where() : nTextEnd
;
3886 if (m_pPostProcessAttrsInfo
&&
3887 m_pPostProcessAttrsInfo
->mnCpStart
== nNext
)
3889 m_pPostProcessAttrsInfo
->mbCopy
= true;
3892 if( (0 <= nNext
) && (nSkipPos
>= nNext
) )
3894 if (nDepthGuard
>= 1024)
3896 SAL_WARN("sw.ww8", "ReadTextAttr hit recursion limit");
3900 nNext
= ReadTextAttr(rTextPos
, nTextEnd
, rbStartLine
, nDepthGuard
+ 1);
3901 bDoPlcxManPlusPLus
= false;
3902 m_bIgnoreText
= true;
3905 if (m_pPostProcessAttrsInfo
&&
3906 nNext
> m_pPostProcessAttrsInfo
->mnCpEnd
)
3908 m_pPostProcessAttrsInfo
->mbCopy
= false;
3911 while( nSkipPos
>= nNext
);
3912 m_bIgnoreText
= bOldIgnoreText
;
3915 m_xCtrlStck
->KillUnlockedAttrs( *m_pPaM
->GetPoint() );
3916 if( nOldColl
!= m_xPlcxMan
->GetColl() )
3917 ProcessCurrentCollChange(aRes
, nullptr, false);
3923 //Revised 2012.8.16 for the complex attribute presentation of 0x0D in MS
3924 bool SwWW8ImplReader::IsParaEndInCPs(sal_Int32 nStart
, sal_Int32 nEnd
,bool bSdOD
) const
3926 //Revised for performance consideration
3927 if (nStart
== -1 || nEnd
== -1 || nEnd
< nStart
)
3930 return std::any_of(m_aEndParaPos
.rbegin(), m_aEndParaPos
.rend(),
3931 [=](const WW8_CP
& rPos
) {
3932 //Revised 2012.8.16,to the 0x0D,the attribute will have two situations
3933 //*********within***********exact******
3934 //*********but also sample with only left and the position of 0x0d is the edge of the right side***********
3935 return (bSdOD
&& ((nStart
< rPos
&& nEnd
> rPos
) || (nStart
== nEnd
&& rPos
== nStart
))) ||
3936 (!bSdOD
&& (nStart
< rPos
&& nEnd
>= rPos
));
3941 //Clear the para end position recorded in reader intermittently for the least impact on loading performance
3942 void SwWW8ImplReader::ClearParaEndPosition()
3944 if ( !m_aEndParaPos
.empty() )
3945 m_aEndParaPos
.clear();
3948 void SwWW8ImplReader::ReadAttrs(WW8_CP
& rTextPos
, WW8_CP
& rNext
, long nTextEnd
, bool& rbStartLine
)
3950 // Do we have attributes?
3951 if( rTextPos
>= rNext
)
3955 m_aCurrAttrCP
= rTextPos
;
3956 rNext
= ReadTextAttr(rTextPos
, nTextEnd
, rbStartLine
);
3957 if (rTextPos
== rNext
&& rTextPos
>= nTextEnd
)
3960 while( rTextPos
>= rNext
);
3963 else if ( rbStartLine
)
3965 /* No attributes, but still a new line.
3966 * If a line ends with a line break and paragraph attributes or paragraph templates
3967 * do NOT change the line end was not added to the Plcx.Fkp.papx i.e. (nFlags & MAN_MASK_NEW_PAP)
3969 * Due to this we need to set the template here as a kind of special treatment.
3971 if (!m_bCpxStyle
&& m_nCurrentColl
< m_vColl
.size())
3972 SetTextFormatCollAndListLevel(*m_pPaM
, m_vColl
[m_nCurrentColl
]);
3973 rbStartLine
= false;
3978 * CloseAttrEnds to only read the attribute ends at the end of a text or a
3979 * text area (Header, Footnote, ...).
3980 * We ignore attribute starts and fields.
3982 void SwWW8ImplReader::CloseAttrEnds()
3984 // If there are any unclosed sprms then copy them to
3985 // another stack and close the ones that must be closed
3986 std::stack
<sal_uInt16
> aStack
;
3987 m_xPlcxMan
->TransferOpenSprms(aStack
);
3989 while (!aStack
.empty())
3991 sal_uInt16 nSprmId
= aStack
.top();
3992 if ((0 < nSprmId
) && (( eFTN
> nSprmId
) || (0x0800 <= nSprmId
)))
4000 bool SwWW8ImplReader::ReadText(WW8_CP nStartCp
, WW8_CP nTextLen
, ManTypes nType
)
4004 bool bStartLine
= true;
4006 short nDistance
= 0;
4008 m_bWasParaEnd
= false;
4010 m_xCurrentItemSet
.reset();
4013 m_bPgSecBreak
= false;
4015 m_xPlcxMan
.reset(new WW8PLCFMan(m_xSBase
.get(), nType
, nStartCp
));
4016 long nCpOfs
= m_xPlcxMan
->GetCpOfs(); // Offset for Header/Footer, Footnote
4018 WW8_CP nNext
= m_xPlcxMan
->Where();
4019 m_pPreviousNode
= nullptr;
4020 sal_uInt8 nDropLines
= 0;
4021 SwCharFormat
* pNewSwCharFormat
= nullptr;
4022 const SwCharFormat
* pFormat
= nullptr;
4024 bool bValidPos
= checkSeek(*m_pStrm
, m_xSBase
->WW8Cp2Fc(nStartCp
+ nCpOfs
, &m_bIsUnicode
));
4028 WW8_CP l
= nStartCp
;
4029 const WW8_CP nMaxPossible
= WW8_CP_MAX
-nStartCp
;
4030 if (nTextLen
> nMaxPossible
)
4032 SAL_WARN_IF(nTextLen
> nMaxPossible
, "sw.ww8", "TextLen too long");
4033 nTextLen
= nMaxPossible
;
4035 WW8_CP nTextEnd
= nStartCp
+nTextLen
;
4036 while (l
< nTextEnd
)
4038 ReadAttrs( l
, nNext
, nTextEnd
, bStartLine
);// Takes SectionBreaks into account, too
4039 OSL_ENSURE(m_pPaM
->GetNode().GetTextNode(), "Missing txtnode");
4041 if (m_pPostProcessAttrsInfo
!= nullptr)
4047 bStartLine
= ReadChars(l
, nNext
, nTextEnd
, nCpOfs
);
4049 // If the previous paragraph was a dropcap then do not
4050 // create a new txtnode and join the two paragraphs together
4051 if (bStartLine
&& !m_pPreviousNode
) // Line end
4054 if (m_bCareFirstParaEndInToc
)
4056 m_bCareFirstParaEndInToc
= false;
4057 if (m_pPaM
->End() && m_pPaM
->End()->nNode
.GetNode().GetTextNode() && m_pPaM
->End()->nNode
.GetNode().GetTextNode()->Len() == 0)
4060 if (m_bCareLastParaEndInToc
)
4062 m_bCareLastParaEndInToc
= false;
4063 if (m_pPaM
->End() && m_pPaM
->End()->nNode
.GetNode().GetTextNode() && m_pPaM
->End()->nNode
.GetNode().GetTextNode()->Len() == 0)
4068 // We will record the CP of a paragraph end ('0x0D'), if current loading contents is from main stream;
4069 if (m_bOnLoadingMain
)
4070 m_aEndParaPos
.push_back(l
-1);
4071 AppendTextNode(*m_pPaM
->GetPoint());
4075 if (m_pPreviousNode
&& bStartLine
)
4077 SwTextNode
* pEndNd
= m_pPaM
->GetNode().GetTextNode();
4078 const sal_Int32 nDropCapLen
= m_pPreviousNode
->GetText().getLength();
4080 // Need to reset the font size and text position for the dropcap
4082 SwPaM
aTmp(*pEndNd
, 0, *pEndNd
, nDropCapLen
+1);
4083 m_xCtrlStck
->Delete(aTmp
);
4086 // Get the default document dropcap which we can use as our template
4087 const SwFormatDrop
* defaultDrop
=
4088 static_cast<const SwFormatDrop
*>( GetFormatAttr(RES_PARATR_DROP
));
4089 SwFormatDrop
aDrop(*defaultDrop
);
4091 aDrop
.GetLines() = nDropLines
;
4092 aDrop
.GetDistance() = nDistance
;
4093 aDrop
.GetChars() = writer_cast
<sal_uInt8
>(nDropCapLen
);
4094 // Word has no concept of a "whole word dropcap"
4095 aDrop
.GetWholeWord() = false;
4098 aDrop
.SetCharFormat(const_cast<SwCharFormat
*>(pFormat
));
4099 else if(pNewSwCharFormat
)
4100 aDrop
.SetCharFormat(pNewSwCharFormat
);
4102 SwPosition
aStart(*pEndNd
);
4103 m_xCtrlStck
->NewAttr(aStart
, aDrop
);
4104 m_xCtrlStck
->SetAttr(*m_pPaM
->GetPoint(), RES_PARATR_DROP
);
4105 m_pPreviousNode
= nullptr;
4107 else if (m_bDropCap
)
4109 // If we have found a dropcap store the textnode
4110 m_pPreviousNode
= m_pPaM
->GetNode().GetTextNode();
4114 aDCS
= m_xPlcxMan
->GetPapPLCF()->HasSprm(46);
4116 aDCS
= m_xPlcxMan
->GetPapPLCF()->HasSprm(0x442C);
4118 if (aDCS
.pSprm
&& aDCS
.nRemainingData
>= 1)
4119 nDropLines
= (*aDCS
.pSprm
) >> 3;
4120 else // There is no Drop Cap Specifier hence no dropcap
4121 m_pPreviousNode
= nullptr;
4123 SprmResult aDistance
= m_xPlcxMan
->GetPapPLCF()->HasSprm(0x842F);
4124 if (aDistance
.pSprm
&& aDistance
.nRemainingData
>= 2)
4125 nDistance
= SVBT16ToUInt16(aDistance
.pSprm
);
4129 const SwFormatCharFormat
*pSwFormatCharFormat
= nullptr;
4131 if (m_xCurrentItemSet
)
4132 pSwFormatCharFormat
= &(ItemGet
<SwFormatCharFormat
>(*m_xCurrentItemSet
, RES_TXTATR_CHARFMT
));
4134 if (pSwFormatCharFormat
)
4135 pFormat
= pSwFormatCharFormat
->GetCharFormat();
4137 if (m_xCurrentItemSet
&& !pFormat
)
4139 OUString sPrefix
= "WW8Dropcap" + OUString::number(m_nDropCap
++);
4140 pNewSwCharFormat
= m_rDoc
.MakeCharFormat(sPrefix
, m_rDoc
.GetDfltCharFormat());
4141 m_xCurrentItemSet
->ClearItem(RES_CHRATR_ESCAPEMENT
);
4142 pNewSwCharFormat
->SetFormatAttr(*m_xCurrentItemSet
);
4145 m_xCurrentItemSet
.reset();
4149 if (bStartLine
|| m_bWasTabRowEnd
)
4151 // Call all 64 CRs; not for Header and the like
4152 if ((nCrCount
++ & 0x40) == 0 && nType
== MAN_MAINTEXT
&& l
<= nTextLen
)
4154 if (nTextLen
< WW8_CP_MAX
/100)
4155 m_nProgress
= static_cast<sal_uInt16
>(l
* 100 / nTextLen
);
4157 m_nProgress
= static_cast<sal_uInt16
>(l
/ nTextLen
* 100);
4158 m_xProgress
->Update(m_nProgress
); // Update
4162 // If we have encountered a 0x0c which indicates either section of
4163 // pagebreak then look it up to see if it is a section break, and
4164 // if it is not then insert a page break. If it is a section break
4165 // it will be handled as such in the ReadAttrs of the next loop
4168 // We need only to see if a section is ending at this cp,
4169 // the plcf will already be sitting on the correct location
4172 aTemp
.nStartPos
= aTemp
.nEndPos
= WW8_CP_MAX
;
4173 if (m_xPlcxMan
->GetSepPLCF())
4174 m_xPlcxMan
->GetSepPLCF()->GetSprms(&aTemp
);
4175 if ((aTemp
.nStartPos
!= l
) && (aTemp
.nEndPos
!= l
))
4177 // #i39251# - insert text node for page break, if no one inserted.
4178 // #i43118# - refine condition: the anchor
4179 // control stack has to have entries, otherwise it's not needed
4180 // to insert a text node.
4181 if (!bStartLine
&& !m_xAnchorStck
->empty())
4183 AppendTextNode(*m_pPaM
->GetPoint());
4185 m_rDoc
.getIDocumentContentOperations().InsertPoolItem(*m_pPaM
,
4186 SvxFormatBreakItem(SvxBreak::PageBefore
, RES_BREAK
));
4187 m_bFirstParaOfPage
= true;
4188 m_bPgSecBreak
= false;
4193 m_pPreviousNode
= nullptr;
4195 if (m_pPaM
->GetPoint()->nContent
.GetIndex())
4196 AppendTextNode(*m_pPaM
->GetPoint());
4198 if (!m_bInHyperlink
)
4199 bJoined
= JoinNode(*m_pPaM
);
4207 SwWW8ImplReader::SwWW8ImplReader(sal_uInt8 nVersionPara
, SotStorage
* pStorage
,
4208 SvStream
* pSt
, SwDoc
& rD
, const OUString
& rBaseURL
, bool bNewDoc
, bool bSkipImages
, SwPosition
const &rPos
)
4209 : m_pDocShell(rD
.GetDocShell())
4212 , m_pTableStream(nullptr)
4213 , m_pDataStream(nullptr)
4216 , m_aSectionManager(*this)
4217 , m_aExtraneousParas(rD
)
4218 , m_aInsertedTables(rD
)
4219 , m_aSectionNameGenerator(rD
, "WW")
4220 , m_aGrfNameGenerator(bNewDoc
, OUString('G'))
4221 , m_aParaStyleMapper(rD
)
4222 , m_aCharStyleMapper(rD
)
4223 , m_pFlyFormatOfJustInsertedGraphic(nullptr)
4224 , m_pFormatOfJustInsertedApo(nullptr)
4225 , m_pPreviousNumPaM(nullptr)
4226 , m_pPrevNumRule(nullptr)
4227 , m_aTextNodesHavingFirstLineOfstSet()
4228 , m_aTextNodesHavingLeftIndentSet()
4229 , m_pCurrentColl(nullptr)
4230 , m_pDfltTextFormatColl(nullptr)
4231 , m_pStandardFormatColl(nullptr)
4232 , m_pDrawModel(nullptr)
4233 , m_pDrawPg(nullptr)
4234 , m_pNumFieldType(nullptr)
4235 , m_sBaseURL(rBaseURL
)
4239 , m_bRegardHindiDigits( false )
4240 , m_bDrawCpOValid( false )
4246 , m_eTextCharSet(RTL_TEXTENCODING_ASCII_US
)
4247 , m_eStructCharSet(RTL_TEXTENCODING_ASCII_US
)
4248 , m_eHardCharSet(RTL_TEXTENCODING_DONTKNOW
)
4252 , m_nLFOPosition(USHRT_MAX
)
4259 , m_nWantedVersion(nVersionPara
)
4260 , m_nSwNumLevel(0xff)
4261 , m_nWwNumType(0xff)
4262 , m_nListLevel(WW8ListManager::nMaxLevel
)
4263 , m_bNewDoc(bNewDoc
)
4264 , m_bSkipImages(bSkipImages
)
4265 , m_bReadNoTable(false)
4266 , m_bPgSecBreak(false)
4269 , m_bTxbxFlySection(false)
4270 , m_bHasBorder(false)
4272 , m_bIgnoreText(false)
4274 , m_bWasTabRowEnd(false)
4275 , m_bWasTabCellEnd(false)
4277 , m_bHdFtFootnoteEdn(false)
4278 , m_bFootnoteEdn(false)
4279 , m_bIsHeader(false)
4280 , m_bIsFooter(false)
4281 , m_bIsUnicode(false)
4282 , m_bCpxStyle(false)
4283 , m_bStyNormal(false)
4284 , m_bWWBugNormal(false)
4285 , m_bNoAttrImport(false)
4286 , m_bInHyperlink(false)
4287 , m_bWasParaEnd(false)
4292 , m_bEmbeddObj(false)
4293 , m_bCurrentAND_fNumberAcross(false)
4294 , m_bNoLnNumYet(true)
4295 , m_bFirstPara(true)
4296 , m_bFirstParaOfPage(false)
4297 , m_bParaAutoBefore(false)
4298 , m_bParaAutoAfter(false)
4302 , m_bReadTable(false)
4303 , m_bLoadingTOXCache(false)
4304 , m_nEmbeddedTOXLevel(0)
4305 , m_bLoadingTOXHyperlink(false)
4306 , m_pPreviousNode(nullptr)
4307 , m_bCareFirstParaEndInToc(false)
4308 , m_bCareLastParaEndInToc(false)
4311 , m_bOnLoadingMain(false)
4312 , m_bNotifyMacroEventRead(false)
4314 m_pStrm
->SetEndian( SvStreamEndian::LITTLE
);
4315 m_aApos
.push_back(false);
4317 mpCursor
= m_rDoc
.CreateUnoCursor(rPos
);
4320 SwWW8ImplReader::~SwWW8ImplReader()
4324 void SwWW8ImplReader::DeleteStack(std::unique_ptr
<SwFltControlStack
> pStck
)
4328 pStck
->SetAttr( *m_pPaM
->GetPoint(), 0, false);
4329 pStck
->SetAttr( *m_pPaM
->GetPoint(), 0, false);
4333 OSL_ENSURE( false, "WW stack already deleted" );
4337 void wwSectionManager::SetSegmentToPageDesc(const wwSection
&rSection
,
4340 SwPageDesc
&rPage
= *rSection
.mpPage
;
4342 SetNumberingType(rSection
, rPage
);
4344 SwFrameFormat
&rFormat
= rPage
.GetMaster();
4346 if(mrReader
.m_xWDop
->fUseBackGroundInAllmodes
) // #i56806# Make sure mrReader is initialized
4347 mrReader
.GrafikCtor();
4349 if (mrReader
.m_xWDop
->fUseBackGroundInAllmodes
&& mrReader
.m_xMSDffManager
)
4351 tools::Rectangle
aRect(0, 0, 100, 100); // A dummy, we don't care about the size
4352 SvxMSDffImportData
aData(aRect
);
4353 SdrObject
* pObject
= nullptr;
4354 if (mrReader
.m_xMSDffManager
->GetShape(0x401, pObject
, aData
) && !aData
.empty())
4356 // Only handle shape if it is a background shape
4357 if (aData
.begin()->get()->nFlags
& ShapeFlag::Background
)
4359 SfxItemSet
aSet(rFormat
.GetAttrSet());
4360 mrReader
.MatchSdrItemsIntoFlySet(pObject
, aSet
, mso_lineSimple
,
4361 mso_lineSolid
, mso_sptRectangle
, aRect
);
4362 rFormat
.SetFormatAttr(aSet
.Get(RES_BACKGROUND
));
4365 SdrObject::Free(pObject
);
4367 wwULSpaceData aULData
;
4368 GetPageULData(rSection
, aULData
);
4369 SetPageULSpaceItems(rFormat
, aULData
, rSection
);
4371 rPage
.SetVerticalAdjustment( rSection
.mnVerticalAdjustment
);
4373 SetPage(rPage
, rFormat
, rSection
, bIgnoreCols
);
4375 if (!(rSection
.maSep
.pgbApplyTo
& 1))
4376 SwWW8ImplReader::SetPageBorder(rFormat
, rSection
);
4377 if (!(rSection
.maSep
.pgbApplyTo
& 2))
4378 SwWW8ImplReader::SetPageBorder(rPage
.GetFirstMaster(), rSection
);
4380 mrReader
.SetDocumentGrid(rFormat
, rSection
);
4383 void wwSectionManager::SetUseOn(wwSection
&rSection
)
4385 bool bMirror
= mrReader
.m_xWDop
->fMirrorMargins
||
4386 mrReader
.m_xWDop
->doptypography
.m_f2on1
;
4388 UseOnPage eUseBase
= bMirror
? UseOnPage::Mirror
: UseOnPage::All
;
4389 UseOnPage eUse
= eUseBase
;
4390 if (!mrReader
.m_xWDop
->fFacingPages
)
4391 eUse
|= UseOnPage::HeaderShare
| UseOnPage::FooterShare
;
4392 if (!rSection
.HasTitlePage())
4393 eUse
|= UseOnPage::FirstShare
;
4395 OSL_ENSURE(rSection
.mpPage
, "Makes no sense to call me with no pages to set");
4396 if (rSection
.mpPage
)
4397 rSection
.mpPage
->WriteUseOn(eUse
);
4401 * Set the page descriptor on this node, handle the different cases for a text
4404 static void GiveNodePageDesc(SwNodeIndex
const &rIdx
, const SwFormatPageDesc
&rPgDesc
,
4408 If it's a table here, apply the pagebreak to the table
4409 properties, otherwise we add it to the para at this
4412 if (rIdx
.GetNode().IsTableNode())
4415 rIdx
.GetNode().GetTableNode()->GetTable();
4416 SwFrameFormat
* pApply
= rTable
.GetFrameFormat();
4417 OSL_ENSURE(pApply
, "impossible");
4419 pApply
->SetFormatAttr(rPgDesc
);
4423 SwPosition
aPamStart(rIdx
);
4424 aPamStart
.nContent
.Assign(
4425 rIdx
.GetNode().GetContentNode(), 0);
4426 SwPaM
aPage(aPamStart
);
4428 rDoc
.getIDocumentContentOperations().InsertPoolItem(aPage
, rPgDesc
);
4433 * Map a word section to a writer page descriptor
4435 SwFormatPageDesc
wwSectionManager::SetSwFormatPageDesc(mySegIter
const &rIter
,
4436 mySegIter
const &rStart
, bool bIgnoreCols
)
4438 if (mrReader
.m_bNewDoc
&& rIter
== rStart
)
4441 mrReader
.m_rDoc
.getIDocumentStylePoolAccess().GetPageDescFromPool(RES_POOLPAGE_STANDARD
);
4445 rIter
->mpPage
= mrReader
.m_rDoc
.MakePageDesc(
4446 SwViewShell::GetShellRes()->GetPageDescName(mnDesc
, ShellResource::NORMAL_PAGE
),
4449 OSL_ENSURE(rIter
->mpPage
, "no page!");
4451 return SwFormatPageDesc();
4453 // Set page before hd/ft
4454 const wwSection
*pPrevious
= nullptr;
4455 if (rIter
!= rStart
)
4456 pPrevious
= &(*(rIter
-1));
4457 SetHdFt(*rIter
, std::distance(rStart
, rIter
), pPrevious
);
4460 // Set hd/ft after set page
4461 SetSegmentToPageDesc(*rIter
, bIgnoreCols
);
4463 SwFormatPageDesc
aRet(rIter
->mpPage
);
4465 rIter
->mpPage
->SetFollow(rIter
->mpPage
);
4467 if (rIter
->PageRestartNo())
4468 aRet
.SetNumOffset(rIter
->PageStartAt());
4474 void wwSectionManager::InsertSegments()
4476 mySegIter aEnd
= maSegments
.end();
4477 mySegIter aStart
= maSegments
.begin();
4478 for (mySegIter aIter
= aStart
; aIter
!= aEnd
; ++aIter
)
4480 // If the section is of type "New column" (0x01), then simply insert a column break.
4481 // But only if there actually are columns on the page, otherwise a column break
4482 // seems to be handled like a page break by MSO.
4483 if ( aIter
->maSep
.bkc
== 1 && aIter
->maSep
.ccolM1
> 0 )
4485 SwPaM
start( aIter
->maStart
);
4486 mrReader
.m_rDoc
.getIDocumentContentOperations().InsertPoolItem( start
, SvxFormatBreakItem(SvxBreak::ColumnBefore
, RES_BREAK
));
4490 mySegIter aNext
= aIter
+1;
4491 mySegIter aPrev
= (aIter
== aStart
) ? aIter
: aIter
-1;
4493 // If two following sections are different in following properties, Word will interpret a continuous
4494 // section break between them as if it was a section break next page.
4495 bool bThisAndPreviousAreCompatible
= ((aIter
->GetPageWidth() == aPrev
->GetPageWidth()) &&
4496 (aIter
->GetPageHeight() == aPrev
->GetPageHeight()) && (aIter
->IsLandScape() == aPrev
->IsLandScape()));
4498 bool bInsertSection
= (aIter
!= aStart
) && aIter
->IsContinuous() && bThisAndPreviousAreCompatible
;
4499 bool bInsertPageDesc
= !bInsertSection
;
4500 // HACK Force new pagedesc if margins change, otherwise e.g. floating tables may be anchored improperly.
4501 if( aIter
->maSep
.dyaTop
!= aPrev
->maSep
.dyaTop
|| aIter
->maSep
.dyaBottom
!= aPrev
->maSep
.dyaBottom
4502 || aIter
->maSep
.dxaLeft
!= aPrev
->maSep
.dxaLeft
|| aIter
->maSep
.dxaRight
!= aPrev
->maSep
.dxaRight
)
4503 bInsertPageDesc
= true;
4504 bool bProtected
= SectionIsProtected(*aIter
); // do we really need this ?? I guess I have a different logic in editshell which disables this...
4506 if (bInsertPageDesc
)
4509 If a cont section follows this section then we won't be
4510 creating a page desc with 2+ cols as we cannot host a one
4511 col section in a 2+ col pagedesc and make it look like
4512 word. But if the current section actually has columns then
4513 we are forced to insert a section here as well as a page
4517 bool bIgnoreCols
= bInsertSection
;
4518 bool bThisAndNextAreCompatible
= (aNext
== aEnd
) ||
4519 ((aIter
->GetPageWidth() == aNext
->GetPageWidth()) &&
4520 (aIter
->GetPageHeight() == aNext
->GetPageHeight()) &&
4521 (aIter
->IsLandScape() == aNext
->IsLandScape()));
4523 if ((aNext
!= aEnd
&& aNext
->IsContinuous() && bThisAndNextAreCompatible
) || bProtected
)
4526 if ((aIter
->NoCols() > 1) || bProtected
)
4527 bInsertSection
= true;
4530 SwFormatPageDesc
aDesc(SetSwFormatPageDesc(aIter
, aStart
, bIgnoreCols
));
4531 if (!aDesc
.GetPageDesc())
4534 // special case handling for odd/even section break
4535 // a) as before create a new page style for the section break
4536 // b) set Layout of generated page style to right/left ( according
4537 // to section break odd/even )
4538 // c) create a new style to follow the break page style
4539 if ( aIter
->maSep
.bkc
== 3 || aIter
->maSep
.bkc
== 4 )
4541 // SetSwFormatPageDesc calls some methods that could
4542 // modify aIter (e.g. wwSection ).
4543 // Since we call SetSwFormatPageDesc below to generate the
4544 // 'Following' style of the Break style, it is safer
4545 // to take a copy of the contents of aIter.
4546 wwSection aTmpSection
= *aIter
;
4547 // create a new following page style
4548 SwFormatPageDesc
aFollow(SetSwFormatPageDesc(aIter
, aStart
, bIgnoreCols
));
4549 // restore any contents of aIter trashed by SetSwFormatPageDesc
4550 *aIter
= aTmpSection
;
4552 // Handle the section break
4553 UseOnPage eUseOnPage
= UseOnPage::Left
;
4554 if ( aIter
->maSep
.bkc
== 4 ) // Odd ( right ) Section break
4555 eUseOnPage
= UseOnPage::Right
;
4557 // Keep the share flags.
4558 aDesc
.GetPageDesc()->SetUseOn( eUseOnPage
);
4559 aDesc
.GetPageDesc()->SetFollow( aFollow
.GetPageDesc() );
4562 GiveNodePageDesc(aIter
->maStart
, aDesc
, mrReader
.m_rDoc
);
4565 SwTextNode
* pTextNd
= nullptr;
4568 // Start getting the bounds of this section
4569 SwPaM
aSectPaM(*mrReader
.m_pPaM
, mrReader
.m_pPaM
);
4570 SwNodeIndex
aAnchor(aSectPaM
.GetPoint()->nNode
);
4573 aAnchor
= aNext
->maStart
;
4574 aSectPaM
.GetPoint()->nNode
= aAnchor
;
4575 aSectPaM
.GetPoint()->nContent
.Assign(
4576 aNext
->maStart
.GetNode().GetContentNode(), 0);
4577 aSectPaM
.Move(fnMoveBackward
);
4580 const SwPosition
* pPos
= aSectPaM
.GetPoint();
4581 SwTextNode
const*const pSttNd
= pPos
->nNode
.GetNode().GetTextNode();
4582 const SwTableNode
* pTableNd
= pSttNd
? pSttNd
->FindTableNode() : nullptr;
4586 mrReader
.m_rDoc
.GetNodes().MakeTextNode(aAnchor
,
4587 mrReader
.m_rDoc
.getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_TEXT
));
4589 aSectPaM
.GetPoint()->nNode
.Assign(*pTextNd
);
4590 aSectPaM
.GetPoint()->nContent
.Assign(
4591 aSectPaM
.GetContentNode(), 0);
4596 aSectPaM
.GetPoint()->nNode
= aIter
->maStart
;
4597 aSectPaM
.GetPoint()->nContent
.Assign(
4598 aSectPaM
.GetContentNode(), 0);
4600 bool bHasOwnHdFt
= false;
4602 In this nightmare scenario the continuous section has its own
4603 headers and footers so we will try and find a hard page break
4604 between here and the end of the section and put the headers and
4607 if (!bInsertPageDesc
)
4610 mrReader
.HasOwnHeaderFooter(
4611 aIter
->maSep
.grpfIhdt
& ~(WW8_HEADER_FIRST
| WW8_FOOTER_FIRST
),
4612 aIter
->maSep
.grpfIhdt
, std::distance(aStart
, aIter
)
4617 // #i40766# Need to cache the page descriptor in case there is
4618 // no page break in the section
4619 SwPageDesc
*pOrig
= aIter
->mpPage
;
4620 bool bFailed
= true;
4621 SwFormatPageDesc
aDesc(SetSwFormatPageDesc(aIter
, aStart
, true));
4622 if (aDesc
.GetPageDesc())
4624 sal_uLong nStart
= aSectPaM
.Start()->nNode
.GetIndex();
4625 sal_uLong nEnd
= aSectPaM
.End()->nNode
.GetIndex();
4626 for(; nStart
<= nEnd
; ++nStart
)
4628 SwNode
* pNode
= mrReader
.m_rDoc
.GetNodes()[nStart
];
4631 if (sw::util::HasPageBreak(*pNode
))
4633 SwNodeIndex
aIdx(*pNode
);
4634 GiveNodePageDesc(aIdx
, aDesc
, mrReader
.m_rDoc
);
4642 aIter
->mpPage
= pOrig
;
4646 // End getting the bounds of this section, quite a job eh?
4647 SwSectionFormat
*pRet
= InsertSection(aSectPaM
, *aIter
);
4648 // The last section if continuous is always unbalanced
4651 // Set the columns to be UnBalanced if that compatibility option is set
4652 if (mrReader
.m_xWDop
->fNoColumnBalance
)
4653 pRet
->SetFormatAttr(SwFormatNoBalancedColumns(true));
4656 // Otherwise set to unbalanced if the following section is
4657 // not continuous, (which also means that the last section
4659 if (aNext
== aEnd
|| !aNext
->IsContinuous())
4660 pRet
->SetFormatAttr(SwFormatNoBalancedColumns(true));
4667 SwNodeIndex
aIdx(*pTextNd
);
4669 mrReader
.m_rDoc
.getIDocumentContentOperations().DelFullPara(aTest
);
4675 void wwExtraneousParas::delete_all_from_doc()
4677 auto aEnd
= m_aTextNodes
.rend();
4678 for (auto aI
= m_aTextNodes
.rbegin(); aI
!= aEnd
; ++aI
)
4680 SwTextNode
*pTextNode
= *aI
;
4681 SwNodeIndex
aIdx(*pTextNode
);
4683 m_rDoc
.getIDocumentContentOperations().DelFullPara(aTest
);
4685 m_aTextNodes
.clear();
4688 void SwWW8ImplReader::StoreMacroCmds()
4690 if (m_xWwFib
->m_lcbCmds
)
4692 bool bValidPos
= checkSeek(*m_pTableStream
, m_xWwFib
->m_fcCmds
);
4696 uno::Reference
< embed::XStorage
> xRoot(m_pDocShell
->GetStorage());
4703 NotifyMacroEventRead();
4705 uno::Reference
< io::XStream
> xStream
=
4706 xRoot
->openStreamElement( SL::aMSMacroCmds
, embed::ElementModes::READWRITE
);
4707 std::unique_ptr
<SvStream
> xOutStream(::utl::UcbStreamHelper::CreateStream(xStream
));
4709 sal_uInt32 lcbCmds
= std::min
<sal_uInt32
>(m_xWwFib
->m_lcbCmds
, m_pTableStream
->remainingSize());
4710 std::unique_ptr
<sal_uInt8
[]> xBuffer(new sal_uInt8
[lcbCmds
]);
4711 m_xWwFib
->m_lcbCmds
= m_pTableStream
->ReadBytes(xBuffer
.get(), lcbCmds
);
4712 xOutStream
->WriteBytes(xBuffer
.get(), m_xWwFib
->m_lcbCmds
);
4720 void SwWW8ImplReader::ReadDocVars()
4722 std::vector
<OUString
> aDocVarStrings
;
4723 std::vector
<ww::bytes
> aDocVarStringIds
;
4724 std::vector
<OUString
> aDocValueStrings
;
4725 WW8ReadSTTBF(!m_bVer67
, *m_pTableStream
, m_xWwFib
->m_fcStwUser
,
4726 m_xWwFib
->m_lcbStwUser
, m_bVer67
? 2 : 0, m_eStructCharSet
,
4727 aDocVarStrings
, &aDocVarStringIds
, &aDocValueStrings
);
4729 uno::Reference
<document::XDocumentPropertiesSupplier
> xDPS(
4730 m_pDocShell
->GetModel(), uno::UNO_QUERY_THROW
);
4731 uno::Reference
<document::XDocumentProperties
> xDocProps(
4732 xDPS
->getDocumentProperties());
4733 OSL_ENSURE(xDocProps
.is(), "DocumentProperties is null");
4734 uno::Reference
<beans::XPropertyContainer
> xUserDefinedProps
=
4735 xDocProps
->getUserDefinedProperties();
4736 OSL_ENSURE(xUserDefinedProps
.is(), "UserDefinedProperties is null");
4738 for(size_t i
=0; i
<aDocVarStrings
.size(); i
++)
4740 const OUString
&rName
= aDocVarStrings
[i
];
4744 xUserDefinedProps
->addProperty( rName
,
4745 beans::PropertyAttribute::REMOVABLE
,
4747 } catch (const uno::Exception
&) {
4757 void SwWW8ImplReader::ReadDocInfo()
4761 uno::Reference
<document::XDocumentPropertiesSupplier
> xDPS(
4762 m_pDocShell
->GetModel(), uno::UNO_QUERY_THROW
);
4763 uno::Reference
<document::XDocumentProperties
> xDocProps(
4764 xDPS
->getDocumentProperties());
4765 OSL_ENSURE(xDocProps
.is(), "DocumentProperties is null");
4769 if ( m_xWwFib
->m_fDot
)
4771 OUString sTemplateURL
;
4772 SfxMedium
* pMedium
= m_pDocShell
->GetMedium();
4775 const OUString
& aName
= pMedium
->GetName();
4776 INetURLObject
aURL( aName
);
4777 sTemplateURL
= aURL
.GetMainURL(INetURLObject::DecodeMechanism::ToIUri
);
4778 if ( !sTemplateURL
.isEmpty() )
4779 xDocProps
->setTemplateURL( sTemplateURL
);
4782 else if (m_xWwFib
->m_lcbSttbfAssoc
) // not a template, and has a SttbfAssoc
4784 auto nCur
= m_pTableStream
->Tell();
4786 // point at tgc record
4787 if (!checkSeek(*m_pTableStream
, m_xWwFib
->m_fcSttbfAssoc
) || !aSttb
.Read(*m_pTableStream
))
4788 SAL_WARN("sw.ww8", "** Read of SttbAssoc data failed!!!! ");
4789 m_pTableStream
->Seek( nCur
); // return to previous position, is that necessary?
4790 OUString sPath
= aSttb
.getStringAtIndex( 0x1 );
4792 // attempt to convert to url (won't work for obvious reasons on linux)
4793 if ( !sPath
.isEmpty() )
4794 osl::FileBase::getFileURLFromSystemPath( sPath
, aURL
);
4796 xDocProps
->setTemplateURL( aURL
);
4798 xDocProps
->setTemplateURL( sPath
);
4801 sfx2::LoadOlePropertySet(xDocProps
, m_pStg
);
4806 static void lcl_createTemplateToProjectEntry( const uno::Reference
< container::XNameContainer
>& xPrjNameCache
, const OUString
& sTemplatePathOrURL
, const OUString
& sVBAProjName
)
4808 if ( xPrjNameCache
.is() )
4811 aObj
.SetURL( sTemplatePathOrURL
);
4812 bool bIsURL
= aObj
.GetProtocol() != INetProtocol::NotValid
;
4815 aURL
= sTemplatePathOrURL
;
4818 osl::FileBase::getFileURLFromSystemPath( sTemplatePathOrURL
, aURL
);
4819 aObj
.SetURL( aURL
);
4823 OUString templateNameWithExt
= aObj
.GetLastName();
4824 OUString templateName
;
4825 sal_Int32 nIndex
= templateNameWithExt
.lastIndexOf( '.' );
4828 templateName
= templateNameWithExt
.copy( 0, nIndex
);
4829 xPrjNameCache
->insertByName( templateName
, uno::makeAny( sVBAProjName
) );
4832 catch( const uno::Exception
& )
4838 class WW8Customizations
4840 SvStream
* mpTableStream
;
4843 WW8Customizations( SvStream
*, WW8Fib
const & );
4844 void Import( SwDocShell
* pShell
);
4847 WW8Customizations::WW8Customizations( SvStream
* pTableStream
, WW8Fib
const & rFib
) : mpTableStream(pTableStream
), mWw8Fib( rFib
)
4851 void WW8Customizations::Import( SwDocShell
* pShell
)
4853 if ( mWw8Fib
.m_lcbCmds
== 0 || !IsEightPlus(mWw8Fib
.GetFIBVersion()) )
4858 long nCur
= mpTableStream
->Tell();
4859 if (!checkSeek(*mpTableStream
, mWw8Fib
.m_fcCmds
)) // point at tgc record
4861 SAL_WARN("sw.ww8", "** Seek to Customization data failed!!!! ");
4864 bool bReadResult
= aTCG
.Read( *mpTableStream
);
4865 mpTableStream
->Seek( nCur
); // return to previous position, is that necessary?
4868 SAL_WARN("sw.ww8", "** Read of Customization data failed!!!! ");
4871 aTCG
.ImportCustomToolBar( *pShell
);
4875 SAL_WARN("sw.ww8", "** Read of Customization data failed!!!! epically");
4879 void SwWW8ImplReader::ReadGlobalTemplateSettings( const OUString
& sCreatedFrom
, const uno::Reference
< container::XNameContainer
>& xPrjNameCache
)
4881 if (utl::ConfigManager::IsFuzzing())
4884 SvtPathOptions aPathOpt
;
4885 const OUString
& aAddinPath
= aPathOpt
.GetAddinPath();
4886 uno::Sequence
< OUString
> sGlobalTemplates
;
4888 // first get the autoload addins in the directory STARTUP
4889 uno::Reference
<ucb::XSimpleFileAccess3
> xSFA(ucb::SimpleFileAccess::create(::comphelper::getProcessComponentContext()));
4891 if( xSFA
->isFolder( aAddinPath
) )
4892 sGlobalTemplates
= xSFA
->getFolderContents( aAddinPath
, false );
4894 for ( const auto& rGlobalTemplate
: sGlobalTemplates
)
4897 aObj
.SetURL( rGlobalTemplate
);
4898 bool bIsURL
= aObj
.GetProtocol() != INetProtocol::NotValid
;
4901 aURL
= rGlobalTemplate
;
4903 osl::FileBase::getFileURLFromSystemPath( rGlobalTemplate
, aURL
);
4904 if ( !aURL
.endsWithIgnoreAsciiCase( ".dot" ) || ( !sCreatedFrom
.isEmpty() && sCreatedFrom
== aURL
) )
4905 continue; // don't try and read the same document as ourselves
4907 tools::SvRef
<SotStorage
> rRoot
= new SotStorage( aURL
, StreamMode::STD_READWRITE
);
4909 BasicProjImportHelper
aBasicImporter( *m_pDocShell
);
4910 // Import vba via oox filter
4911 aBasicImporter
.import( m_pDocShell
->GetMedium()->GetInputStream() );
4912 lcl_createTemplateToProjectEntry( xPrjNameCache
, aURL
, aBasicImporter
.getProjectName() );
4913 // Read toolbars & menus
4914 tools::SvRef
<SotStorageStream
> refMainStream
= rRoot
->OpenSotStream( "WordDocument");
4915 refMainStream
->SetEndian(SvStreamEndian::LITTLE
);
4916 WW8Fib
aWwFib( *refMainStream
, 8 );
4917 tools::SvRef
<SotStorageStream
> xTableStream
=
4918 rRoot
->OpenSotStream(aWwFib
.m_fWhichTableStm
? SL::a1Table
: SL::a0Table
, StreamMode::STD_READ
);
4920 if (xTableStream
.is() && ERRCODE_NONE
== xTableStream
->GetError())
4922 xTableStream
->SetEndian(SvStreamEndian::LITTLE
);
4923 WW8Customizations
aGblCustomisations( xTableStream
.get(), aWwFib
);
4924 aGblCustomisations
.Import( m_pDocShell
);
4929 ErrCode
SwWW8ImplReader::CoreLoad(WW8Glossary
const *pGloss
)
4931 m_rDoc
.SetDocumentType( SwDoc::DOCTYPE_MSWORD
);
4932 if (m_bNewDoc
&& m_pStg
&& !pGloss
)
4934 // Initialize RDF metadata, to be able to add statements during the import.
4937 uno::Reference
<frame::XModel
> const xModel(m_rDoc
.GetDocShell()->GetBaseModel());
4938 uno::Reference
<rdf::XDocumentMetadataAccess
> xDocumentMetadataAccess(xModel
, uno::UNO_QUERY_THROW
);
4939 uno::Reference
<uno::XComponentContext
> xComponentContext(comphelper::getProcessComponentContext());
4940 uno::Reference
<embed::XStorage
> xStorage
= comphelper::OStorageHelper::GetTemporaryStorage();
4941 const uno::Reference
<rdf::XURI
> xBaseURI(sfx2::createBaseURI(xComponentContext
, xModel
, m_sBaseURL
));
4942 uno::Reference
<task::XInteractionHandler
> xHandler
;
4943 xDocumentMetadataAccess
->loadMetadataFromStorage(xStorage
, xBaseURI
, xHandler
);
4945 catch (const uno::Exception
&)
4947 DBG_UNHANDLED_EXCEPTION("sw.ww8", "failed to initialize RDF metadata");
4952 ::ww8::WW8FibData
* pFibData
= new ::ww8::WW8FibData();
4954 if (m_xWwFib
->m_fReadOnlyRecommended
)
4955 pFibData
->setReadOnlyRecommended(true);
4957 pFibData
->setReadOnlyRecommended(false);
4959 if (m_xWwFib
->m_fWriteReservation
)
4960 pFibData
->setWriteReservation(true);
4962 pFibData
->setWriteReservation(false);
4964 ::sw::tExternalDataPointer
pExternalFibData(pFibData
);
4966 m_rDoc
.getIDocumentExternalData().setExternalData(::sw::tExternalDataType::FIB
, pExternalFibData
);
4968 ::sw::tExternalDataPointer pSttbfAsoc
4969 (new ::ww8::WW8Sttb
<ww8::WW8Struct
>(*m_pTableStream
, m_xWwFib
->m_fcSttbfAssoc
, m_xWwFib
->m_lcbSttbfAssoc
));
4971 m_rDoc
.getIDocumentExternalData().setExternalData(::sw::tExternalDataType::STTBF_ASSOC
, pSttbfAsoc
);
4973 if (m_xWwFib
->m_fWriteReservation
|| m_xWwFib
->m_fReadOnlyRecommended
)
4975 SwDocShell
* pDocShell
= m_rDoc
.GetDocShell();
4977 pDocShell
->SetReadOnlyUI();
4980 m_pPaM
= mpCursor
.get();
4982 m_xCtrlStck
.reset(new SwWW8FltControlStack(&m_rDoc
, m_nFieldFlags
, *this));
4984 m_xRedlineStack
.reset(new sw::util::RedlineStack(m_rDoc
));
4987 RefFieldStck: Keeps track of bookmarks which may be inserted as
4990 m_xReffedStck
.reset(new SwWW8ReferencedFltEndStack(&m_rDoc
, m_nFieldFlags
));
4991 m_xReffingStck
.reset(new SwWW8FltRefStack(&m_rDoc
, m_nFieldFlags
));
4993 m_xAnchorStck
.reset(new SwWW8FltAnchorStack(&m_rDoc
, m_nFieldFlags
));
4995 size_t nPageDescOffset
= m_rDoc
.GetPageDescCnt();
4997 SwNodeIndex
aSttNdIdx( m_rDoc
.GetNodes() );
4998 SwRelNumRuleSpaces
aRelNumRule(m_rDoc
, m_bNewDoc
);
5000 RedlineFlags eMode
= RedlineFlags::ShowInsert
| RedlineFlags::ShowDelete
;
5002 m_xSprmParser
.reset(new wwSprmParser(*m_xWwFib
));
5004 // Set handy helper variables
5005 m_bVer6
= (6 == m_xWwFib
->m_nVersion
);
5006 m_bVer7
= (7 == m_xWwFib
->m_nVersion
);
5007 m_bVer67
= m_bVer6
|| m_bVer7
;
5008 m_bVer8
= (8 == m_xWwFib
->m_nVersion
);
5010 m_eTextCharSet
= WW8Fib::GetFIBCharset(m_xWwFib
->m_chse
, m_xWwFib
->m_lid
);
5011 m_eStructCharSet
= WW8Fib::GetFIBCharset(m_xWwFib
->m_chseTables
, m_xWwFib
->m_lid
);
5013 m_bWWBugNormal
= m_xWwFib
->m_nProduct
== 0xc03d;
5016 aSttNdIdx
= m_pPaM
->GetPoint()->nNode
;
5018 m_xProgress
.reset(new ImportProgress(m_pDocShell
, 0, 100));
5021 m_xFonts
.reset(new WW8Fonts(*m_pTableStream
, *m_xWwFib
));
5023 // Document Properties
5024 m_xWDop
.reset(new WW8Dop(*m_pTableStream
, m_xWwFib
->m_nFib
, m_xWwFib
->m_fcDop
,
5025 m_xWwFib
->m_lcbDop
));
5031 Import revisioning data: author names
5033 if( m_xWwFib
->m_lcbSttbfRMark
)
5035 ReadRevMarkAuthorStrTabl(*m_pTableStream
,
5036 m_xWwFib
->m_fcSttbfRMark
,
5037 m_xWwFib
->m_lcbSttbfRMark
, m_rDoc
);
5040 // Initialize our String/ID map for Linked Sections
5041 std::vector
<OUString
> aLinkStrings
;
5042 std::vector
<ww::bytes
> aStringIds
;
5044 WW8ReadSTTBF(!m_bVer67
, *m_pTableStream
, m_xWwFib
->m_fcSttbFnm
,
5045 m_xWwFib
->m_lcbSttbFnm
, m_bVer67
? 2 : 0, m_eStructCharSet
,
5046 aLinkStrings
, &aStringIds
);
5048 for (size_t i
=0; i
< aLinkStrings
.size() && i
< aStringIds
.size(); ++i
)
5050 const ww::bytes
& stringId
= aStringIds
[i
];
5051 if (stringId
.size() < sizeof(WW8_STRINGID
))
5053 SAL_WARN("sw.ww8", "SwWW8ImplReader::CoreLoad: WW8_STRINGID is too short");
5056 const WW8_STRINGID
*stringIdStruct
= reinterpret_cast<const WW8_STRINGID
*>(stringId
.data());
5057 m_aLinkStringMap
[SVBT16ToUInt16(stringIdStruct
->nStringId
)] = aLinkStrings
[i
];
5060 ReadDocVars(); // import document variables as meta information.
5062 m_xProgress
->Update(m_nProgress
); // Update
5064 m_xLstManager
.reset(new WW8ListManager(*m_pTableStream
, *this));
5067 first (1) import all styles (see WW8PAR2.CXX)
5068 BEFORE the import of the lists !!
5070 m_xProgress
->Update(m_nProgress
); // Update
5071 m_xStyles
.reset(new WW8RStyle(*m_xWwFib
, this)); // Styles
5072 m_xStyles
->Import();
5075 In the end: (also see WW8PAR3.CXX)
5077 Go through all Styles and attach respective List Format
5078 AFTER we imported the Styles and AFTER we imported the Lists!
5080 m_xProgress
->Update(m_nProgress
); // Update
5081 m_xStyles
->PostProcessStyles();
5083 if (!m_vColl
.empty())
5086 m_xSBase
.reset(new WW8ScannerBase(m_pStrm
,m_pTableStream
,m_pDataStream
, m_xWwFib
.get()));
5088 static const SvxNumType eNumTA
[16] =
5090 SVX_NUM_ARABIC
, SVX_NUM_ROMAN_UPPER
, SVX_NUM_ROMAN_LOWER
,
5091 SVX_NUM_CHARS_UPPER_LETTER_N
, SVX_NUM_CHARS_LOWER_LETTER_N
,
5092 SVX_NUM_ARABIC
, SVX_NUM_ARABIC
, SVX_NUM_ARABIC
,
5093 SVX_NUM_ARABIC
, SVX_NUM_ARABIC
, SVX_NUM_ARABIC
,
5094 SVX_NUM_ARABIC
, SVX_NUM_ARABIC
, SVX_NUM_ARABIC
,
5095 SVX_NUM_ARABIC
, SVX_NUM_ARABIC
5098 if (m_xSBase
->AreThereFootnotes())
5100 static const SwFootnoteNum eNumA
[4] =
5102 FTNNUM_DOC
, FTNNUM_CHAPTER
, FTNNUM_PAGE
, FTNNUM_DOC
5105 SwFootnoteInfo aInfo
= m_rDoc
.GetFootnoteInfo(); // Copy-Ctor private
5107 aInfo
.ePos
= FTNPOS_PAGE
;
5108 aInfo
.eNum
= eNumA
[m_xWDop
->rncFootnote
];
5109 sal_uInt16 nfcFootnoteRef
= m_xWDop
->nfcFootnoteRef
& 0xF;
5110 aInfo
.aFormat
.SetNumberingType( eNumTA
[nfcFootnoteRef
] );
5111 if( m_xWDop
->nFootnote
)
5112 aInfo
.nFootnoteOffset
= m_xWDop
->nFootnote
- 1;
5113 m_rDoc
.SetFootnoteInfo( aInfo
);
5115 if (m_xSBase
->AreThereEndnotes())
5117 SwEndNoteInfo aInfo
= m_rDoc
.GetEndNoteInfo(); // Same as for Footnote
5118 sal_uInt16 nfcEdnRef
= m_xWDop
->nfcEdnRef
& 0xF;
5119 aInfo
.aFormat
.SetNumberingType( eNumTA
[nfcEdnRef
] );
5121 aInfo
.nFootnoteOffset
= m_xWDop
->nEdn
- 1;
5122 m_rDoc
.SetEndNoteInfo( aInfo
);
5125 if (m_xWwFib
->m_lcbPlcfhdd
)
5126 m_xHdFt
.reset(new WW8PLCF_HdFt(m_pTableStream
, *m_xWwFib
, *m_xWDop
));
5130 // inserting into an existing document:
5131 // As only complete paragraphs are inserted, the current one
5132 // needs to be split - once or even twice.
5133 const SwPosition
* pPos
= m_pPaM
->GetPoint();
5135 // split current paragraph to get new paragraph for the insertion
5136 m_rDoc
.getIDocumentContentOperations().SplitNode( *pPos
, false );
5138 // another split, if insertion position was not at the end of the current paragraph.
5139 SwTextNode
const*const pTextNd
= pPos
->nNode
.GetNode().GetTextNode();
5140 if ( pTextNd
->GetText().getLength() )
5142 m_rDoc
.getIDocumentContentOperations().SplitNode( *pPos
, false );
5143 // move PaM back to the newly empty paragraph
5144 m_pPaM
->Move( fnMoveBackward
);
5147 // suppress insertion of tables inside footnotes.
5148 const sal_uLong nNd
= pPos
->nNode
.GetIndex();
5149 m_bReadNoTable
= ( nNd
< m_rDoc
.GetNodes().GetEndOfInserts().GetIndex() &&
5150 m_rDoc
.GetNodes().GetEndOfInserts().StartOfSectionIndex() < nNd
);
5153 m_xProgress
->Update(m_nProgress
); // Update
5155 // loop for each glossary entry and add dummy section node
5158 WW8PLCF
aPlc(*m_pTableStream
, m_xWwFib
->m_fcPlcfglsy
, m_xWwFib
->m_lcbPlcfglsy
, 0);
5160 WW8_CP nStart
, nEnd
;
5163 for (int i
= 0; i
< pGloss
->GetNoStrings(); ++i
, aPlc
.advance())
5165 SwNodeIndex
aIdx( m_rDoc
.GetNodes().GetEndOfContent());
5166 SwTextFormatColl
* pColl
=
5167 m_rDoc
.getIDocumentStylePoolAccess().GetTextCollFromPool(RES_POOLCOLL_STANDARD
,
5169 SwStartNode
*pNode
=
5170 m_rDoc
.GetNodes().MakeTextSection(aIdx
,
5171 SwNormalStartNode
,pColl
);
5172 m_pPaM
->GetPoint()->nNode
= pNode
->GetIndex()+1;
5173 m_pPaM
->GetPoint()->nContent
.Assign(m_pPaM
->GetContentNode(),0);
5174 aPlc
.Get( nStart
, nEnd
, pDummy
);
5175 ReadText(nStart
,nEnd
-nStart
-1,MAN_MAINTEXT
);
5178 else // ordinary case
5180 if (m_bNewDoc
&& m_pStg
) /*meaningless for a glossary */
5182 m_pDocShell
->SetIsTemplate( m_xWwFib
->m_fDot
); // point at tgc record
5183 uno::Reference
<document::XDocumentPropertiesSupplier
> const
5184 xDocPropSupp(m_pDocShell
->GetModel(), uno::UNO_QUERY_THROW
);
5185 uno::Reference
< document::XDocumentProperties
> xDocProps( xDocPropSupp
->getDocumentProperties(), uno::UNO_SET_THROW
);
5187 OUString sCreatedFrom
= xDocProps
->getTemplateURL();
5188 uno::Reference
< container::XNameContainer
> xPrjNameCache
;
5189 uno::Reference
< lang::XMultiServiceFactory
> xSF(m_pDocShell
->GetModel(), uno::UNO_QUERY
);
5191 xPrjNameCache
.set( xSF
->createInstance( "ooo.vba.VBAProjectNameProvider" ), uno::UNO_QUERY
);
5193 // Read Global templates
5194 ReadGlobalTemplateSettings( sCreatedFrom
, xPrjNameCache
);
5196 // Create and insert Word vba Globals
5198 uno::Sequence
< uno::Any
> aArgs(1);
5199 aArgs
[ 0 ] <<= m_pDocShell
->GetModel();
5202 aGlobs
<<= ::comphelper::getProcessServiceFactory()->createInstanceWithArguments( "ooo.vba.word.Globals", aArgs
);
5204 catch (const uno::Exception
&)
5206 SAL_WARN("sw.ww8", "SwWW8ImplReader::CoreLoad: ooo.vba.word.Globals is not available");
5209 #if HAVE_FEATURE_SCRIPTING
5210 if (!utl::ConfigManager::IsFuzzing())
5212 BasicManager
*pBasicMan
= m_pDocShell
->GetBasicManager();
5214 pBasicMan
->SetGlobalUNOConstant( "VBAGlobals", aGlobs
);
5217 BasicProjImportHelper
aBasicImporter( *m_pDocShell
);
5218 // Import vba via oox filter
5219 bool bRet
= aBasicImporter
.import( m_pDocShell
->GetMedium()->GetInputStream() );
5221 lcl_createTemplateToProjectEntry( xPrjNameCache
, sCreatedFrom
, aBasicImporter
.getProjectName() );
5222 WW8Customizations
aCustomisations( m_pTableStream
, *m_xWwFib
);
5223 aCustomisations
.Import( m_pDocShell
);
5226 m_rDoc
.SetContainsMSVBasic(true);
5230 m_bOnLoadingMain
= true;
5231 ReadText(0, m_xWwFib
->m_ccpText
, MAN_MAINTEXT
);
5232 m_bOnLoadingMain
= false;
5235 m_xProgress
->Update(m_nProgress
); // Update
5237 if (m_pDrawPg
&& m_xMSDffManager
&& m_xMSDffManager
->GetShapeOrders())
5239 // Helper array to chain the inserted frames (instead of SdrTextObj)
5240 SvxMSDffShapeTxBxSort aTxBxSort
;
5242 // Ensure correct z-order of read Escher objects
5243 sal_uInt16 nShapeCount
= m_xMSDffManager
->GetShapeOrders()->size();
5245 for (sal_uInt16 nShapeNum
=0; nShapeNum
< nShapeCount
; nShapeNum
++)
5247 SvxMSDffShapeOrder
*pOrder
=
5248 (*m_xMSDffManager
->GetShapeOrders())[nShapeNum
].get();
5249 // Insert Pointer into new Sort array
5250 if (pOrder
->nTxBxComp
&& pOrder
->pFly
)
5251 aTxBxSort
.insert(pOrder
);
5254 if( !aTxBxSort
.empty() )
5256 SwFormatChain aChain
;
5257 for( SvxMSDffShapeTxBxSort::iterator it
= aTxBxSort
.begin(); it
!= aTxBxSort
.end(); ++it
)
5259 SvxMSDffShapeOrder
*pOrder
= *it
;
5261 // Initialize FlyFrame Formats
5262 SwFlyFrameFormat
* pFlyFormat
= pOrder
->pFly
;
5263 SwFlyFrameFormat
* pNextFlyFormat
= nullptr;
5264 SwFlyFrameFormat
* pPrevFlyFormat
= nullptr;
5266 // Determine successor, if we can
5267 SvxMSDffShapeTxBxSort::iterator tmpIter1
= it
;
5269 if( tmpIter1
!= aTxBxSort
.end() )
5271 SvxMSDffShapeOrder
*pNextOrder
= *tmpIter1
;
5272 if ((0xFFFF0000 & pOrder
->nTxBxComp
)
5273 == (0xFFFF0000 & pNextOrder
->nTxBxComp
))
5274 pNextFlyFormat
= pNextOrder
->pFly
;
5276 // Determine predecessor, if we can
5277 if( it
!= aTxBxSort
.begin() )
5279 SvxMSDffShapeTxBxSort::iterator tmpIter2
= it
;
5281 SvxMSDffShapeOrder
*pPrevOrder
= *tmpIter2
;
5282 if ((0xFFFF0000 & pOrder
->nTxBxComp
)
5283 == (0xFFFF0000 & pPrevOrder
->nTxBxComp
))
5284 pPrevFlyFormat
= pPrevOrder
->pFly
;
5286 // If successor or predecessor present, insert the
5287 // chain at the FlyFrame Format
5288 if (pNextFlyFormat
|| pPrevFlyFormat
)
5290 aChain
.SetNext( pNextFlyFormat
);
5291 aChain
.SetPrev( pPrevFlyFormat
);
5292 pFlyFormat
->SetFormatAttr( aChain
);
5298 bool isHideRedlines(false);
5302 if( m_xWDop
->fRevMarking
)
5303 eMode
|= RedlineFlags::On
;
5304 isHideRedlines
= !m_xWDop
->fRMView
;
5307 m_aInsertedTables
.DelAndMakeTableFrames();
5308 m_aSectionManager
.InsertSegments();
5314 m_xFormImpl
.reset();
5316 m_xMSDffManager
.reset();
5321 m_pAtnNames
.reset();
5322 m_xSprmParser
.reset();
5323 m_xProgress
.reset();
5325 m_pDataStream
= nullptr;
5326 m_pTableStream
= nullptr;
5329 DeleteAnchorStack();
5331 m_pLastAnchorPos
.reset();//ensure this is deleted before UpdatePageDescs
5332 // ofz#10994 remove any trailing fly paras before processing redlines
5333 m_xWFlyPara
.reset();
5334 // ofz#12660 remove any trailing fly paras before deleting extra paras
5335 m_xSFlyPara
.reset();
5336 // remove extra paragraphs after attribute ctrl
5337 // stacks etc. are destroyed, and before fields
5339 m_aExtraneousParas
.delete_all_from_doc();
5340 m_xRedlineStack
->closeall(*m_pPaM
->GetPoint());
5341 while (!m_aFrameRedlines
.empty())
5342 m_aFrameRedlines
.pop();
5343 m_xRedlineStack
.reset();
5345 // For i120928,achieve the graphics from the special bookmark with is for graphic bullet
5347 std::vector
<const SwGrfNode
*> vecBulletGrf
;
5348 std::vector
<SwFrameFormat
*> vecFrameFormat
;
5350 IDocumentMarkAccess
* const pMarkAccess
= m_rDoc
.getIDocumentMarkAccess();
5353 IDocumentMarkAccess::const_iterator_t ppBkmk
= pMarkAccess
->findBookmark( "_PictureBullets" );
5354 if ( ppBkmk
!= pMarkAccess
->getBookmarksEnd() &&
5355 IDocumentMarkAccess::GetType(**ppBkmk
) == IDocumentMarkAccess::MarkType::BOOKMARK
)
5357 SwTextNode
* pTextNode
= (*ppBkmk
)->GetMarkStart().nNode
.GetNode().GetTextNode();
5361 const SwpHints
* pHints
= pTextNode
->GetpSwpHints();
5362 for( size_t nHintPos
= 0; pHints
&& nHintPos
< pHints
->Count(); ++nHintPos
)
5364 const SwTextAttr
*pHt
= pHints
->Get(nHintPos
);
5365 if (pHt
->Which() != RES_TXTATR_FLYCNT
)
5367 const sal_Int32 st
= pHt
->GetStart();
5368 if (st
>= (*ppBkmk
)->GetMarkStart().nContent
.GetIndex())
5370 SwFrameFormat
* pFrameFormat
= pHt
->GetFlyCnt().GetFrameFormat();
5371 vecFrameFormat
.push_back(pFrameFormat
);
5372 const SwNodeIndex
* pNdIdx
= pFrameFormat
->GetContent().GetContentIdx();
5373 const SwNodes
* pNodesArray
= (pNdIdx
!= nullptr)
5374 ? &(pNdIdx
->GetNodes())
5376 const SwGrfNode
*pGrf
= (pNodesArray
!= nullptr)
5377 ? dynamic_cast<const SwGrfNode
*>((*pNodesArray
)[pNdIdx
->GetIndex() + 1])
5379 vecBulletGrf
.push_back(pGrf
);
5382 // update graphic bullet information
5383 size_t nCount
= m_xLstManager
->GetWW8LSTInfoNum();
5384 for (size_t i
= 0; i
< nCount
; ++i
)
5386 SwNumRule
* pRule
= m_xLstManager
->GetNumRule(i
);
5387 for (sal_uInt16 j
= 0; j
< MAXLEVEL
; ++j
)
5389 SwNumFormat
aNumFormat(pRule
->Get(j
));
5390 const sal_Int16 nType
= aNumFormat
.GetNumberingType();
5391 const sal_uInt16 nGrfBulletCP
= aNumFormat
.GetGrfBulletCP();
5392 if ( nType
== SVX_NUM_BITMAP
5393 && vecBulletGrf
.size() > nGrfBulletCP
5394 && vecBulletGrf
[nGrfBulletCP
] != nullptr )
5396 Graphic aGraphic
= vecBulletGrf
[nGrfBulletCP
]->GetGrf();
5397 SvxBrushItem
aBrush(aGraphic
, GPOS_AREA
, SID_ATTR_BRUSH
);
5398 const vcl::Font
& aFont
= numfunc::GetDefBulletFont();
5399 int nHeight
= aFont
.GetFontHeight() * 12;
5400 Size
aPrefSize( aGraphic
.GetPrefSize());
5401 if (aPrefSize
.Height() * aPrefSize
.Width() != 0 )
5403 int nWidth
= (nHeight
* aPrefSize
.Width()) / aPrefSize
.Height();
5404 Size
aSize(nWidth
, nHeight
);
5405 aNumFormat
.SetGraphicBrush(&aBrush
, &aSize
);
5409 aNumFormat
.SetNumberingType(SVX_NUM_CHAR_SPECIAL
);
5410 aNumFormat
.SetBulletChar(0x2190);
5412 pRule
->Set( j
, aNumFormat
);
5416 // Remove additional pictures
5417 for (SwFrameFormat
* p
: vecFrameFormat
)
5419 m_rDoc
.getIDocumentLayoutAccess().DelLayoutFormat(p
);
5424 m_xLstManager
.reset();
5427 m_pPosAfterTOC
.reset();
5433 // delete the pam before the call for hide all redlines (Bug 73683)
5435 m_rDoc
.getIDocumentRedlineAccess().SetRedlineFlags(eMode
);
5437 UpdatePageDescs(m_rDoc
, nPageDescOffset
);
5439 // can't set it on the layout or view shell because it doesn't exist yet
5440 m_rDoc
.GetDocumentRedlineManager().SetHideRedlines(isHideRedlines
);
5442 return ERRCODE_NONE
;
5445 ErrCode
SwWW8ImplReader::SetSubStreams(tools::SvRef
<SotStorageStream
> &rTableStream
,
5446 tools::SvRef
<SotStorageStream
> &rDataStream
)
5448 ErrCode nErrRet
= ERRCODE_NONE
;
5449 // 6 stands for "6 OR 7", 7 stands for "ONLY 7"
5450 switch (m_xWwFib
->m_nVersion
)
5454 m_pTableStream
= m_pStrm
;
5455 m_pDataStream
= m_pStrm
;
5460 OSL_ENSURE( m_pStg
, "Version 8 always needs to have a Storage!!" );
5461 nErrRet
= ERR_SWG_READ_ERROR
;
5465 rTableStream
= m_pStg
->OpenSotStream(
5466 m_xWwFib
->m_fWhichTableStm
? SL::a1Table
: SL::a0Table
,
5467 StreamMode::STD_READ
);
5469 m_pTableStream
= rTableStream
.get();
5470 m_pTableStream
->SetEndian( SvStreamEndian::LITTLE
);
5472 rDataStream
= m_pStg
->OpenSotStream(SL::aData
, StreamMode::STD_READ
);
5474 if (rDataStream
.is() && ERRCODE_NONE
== rDataStream
->GetError())
5476 m_pDataStream
= rDataStream
.get();
5477 m_pDataStream
->SetEndian(SvStreamEndian::LITTLE
);
5480 m_pDataStream
= m_pStrm
;
5484 OSL_ENSURE( false, "We forgot to encode nVersion!" );
5485 nErrRet
= ERR_SWG_READ_ERROR
;
5493 std::unique_ptr
<utl::TempFile
> MakeTemp(SvFileStream
&rSt
)
5495 std::unique_ptr
<utl::TempFile
> pT(new utl::TempFile
);
5496 pT
->EnableKillingFile();
5497 rSt
.Open(pT
->GetFileName(), StreamMode::READWRITE
| StreamMode::SHARE_DENYWRITE
);
5501 #define WW_BLOCKSIZE 0x200
5503 void DecryptRC4(msfilter::MSCodec97
& rCtx
, SvStream
&rIn
, SvStream
&rOut
)
5505 const std::size_t nLen
= rIn
.TellEnd();
5508 sal_uInt8 in
[WW_BLOCKSIZE
];
5509 for (std::size_t nI
= 0, nBlock
= 0; nI
< nLen
; nI
+= WW_BLOCKSIZE
, ++nBlock
)
5511 std::size_t nBS
= std::min
<size_t>(nLen
- nI
, WW_BLOCKSIZE
);
5512 nBS
= rIn
.ReadBytes(in
, nBS
);
5513 rCtx
.InitCipher(nBlock
);
5514 rCtx
.Decode(in
, nBS
, in
, nBS
);
5515 rOut
.WriteBytes(in
, nBS
);
5519 void DecryptXOR(msfilter::MSCodec_XorWord95
&rCtx
, SvStream
&rIn
, SvStream
&rOut
)
5521 std::size_t nSt
= rIn
.Tell();
5522 std::size_t nLen
= rIn
.TellEnd();
5527 sal_uInt8 in
[0x4096];
5528 for (std::size_t nI
= nSt
; nI
< nLen
; nI
+= 0x4096)
5530 std::size_t nBS
= std::min
<size_t>(nLen
- nI
, 0x4096 );
5531 nBS
= rIn
.ReadBytes(in
, nBS
);
5532 rCtx
.Decode(in
, nBS
);
5533 rOut
.WriteBytes(in
, nBS
);
5537 // moan, copy and paste :-(
5538 OUString
QueryPasswordForMedium(SfxMedium
& rMedium
)
5542 const SfxItemSet
* pSet
= rMedium
.GetItemSet();
5543 const SfxPoolItem
*pPasswordItem
;
5545 if(pSet
&& SfxItemState::SET
== pSet
->GetItemState(SID_PASSWORD
, true, &pPasswordItem
))
5546 aPassw
= static_cast<const SfxStringItem
*>(pPasswordItem
)->GetValue();
5551 uno::Reference
< task::XInteractionHandler
> xHandler( rMedium
.GetInteractionHandler() );
5554 ::comphelper::DocPasswordRequest
* pRequest
= new ::comphelper::DocPasswordRequest(
5555 ::comphelper::DocPasswordRequestType::MS
, task::PasswordRequestMode_PASSWORD_ENTER
,
5556 INetURLObject(rMedium
.GetOrigURL())
5557 .GetLastName(INetURLObject::DecodeMechanism::WithCharset
));
5558 uno::Reference
< task::XInteractionRequest
> xRequest( pRequest
);
5560 xHandler
->handle( xRequest
);
5562 if( pRequest
->isPassword() )
5563 aPassw
= pRequest
->getPassword();
5566 catch( const uno::Exception
& )
5574 uno::Sequence
< beans::NamedValue
> InitXorWord95Codec( ::msfilter::MSCodec_XorWord95
& rCodec
, SfxMedium
& rMedium
, WW8Fib
const * pWwFib
)
5576 uno::Sequence
< beans::NamedValue
> aEncryptionData
;
5577 const SfxUnoAnyItem
* pEncryptionData
= SfxItemSet::GetItem
<SfxUnoAnyItem
>(rMedium
.GetItemSet(), SID_ENCRYPTIONDATA
, false);
5578 if ( pEncryptionData
&& ( pEncryptionData
->GetValue() >>= aEncryptionData
) && !rCodec
.InitCodec( aEncryptionData
) )
5579 aEncryptionData
.realloc( 0 );
5581 if ( !aEncryptionData
.hasElements() )
5583 OUString sUniPassword
= QueryPasswordForMedium( rMedium
);
5585 OString
sPassword(OUStringToOString(sUniPassword
,
5586 WW8Fib::GetFIBCharset(pWwFib
->m_chseTables
, pWwFib
->m_lid
)));
5588 sal_Int32 nLen
= sPassword
.getLength();
5591 sal_uInt8 pPassword
[16];
5592 memcpy(pPassword
, sPassword
.getStr(), nLen
);
5593 memset(pPassword
+nLen
, 0, sizeof(pPassword
)-nLen
);
5595 rCodec
.InitKey( pPassword
);
5596 aEncryptionData
= rCodec
.GetEncryptionData();
5598 // the export supports RC4 algorithm only, so we have to
5599 // generate the related EncryptionData as well, so that Save
5600 // can export the document without asking for a password;
5601 // as result there will be EncryptionData for both algorithms
5602 // in the MediaDescriptor
5603 ::msfilter::MSCodec_Std97 aCodec97
;
5605 rtlRandomPool aRandomPool
= rtl_random_createPool();
5606 sal_uInt8 pDocId
[ 16 ];
5607 rtl_random_getBytes( aRandomPool
, pDocId
, 16 );
5609 rtl_random_destroyPool( aRandomPool
);
5611 sal_uInt16 pStd97Pass
[16];
5612 memset( pStd97Pass
, 0, sizeof( pStd97Pass
) );
5613 for( sal_Int32 nChar
= 0; nChar
< nLen
; ++nChar
)
5614 pStd97Pass
[nChar
] = sUniPassword
[nChar
];
5616 aCodec97
.InitKey( pStd97Pass
, pDocId
);
5618 // merge the EncryptionData, there should be no conflicts
5619 ::comphelper::SequenceAsHashMap
aEncryptionHash( aEncryptionData
);
5620 aEncryptionHash
.update( ::comphelper::SequenceAsHashMap( aCodec97
.GetEncryptionData() ) );
5621 aEncryptionHash
>> aEncryptionData
;
5625 return aEncryptionData
;
5628 uno::Sequence
< beans::NamedValue
> Init97Codec(msfilter::MSCodec97
& rCodec
, sal_uInt8
const pDocId
[16], SfxMedium
& rMedium
)
5630 uno::Sequence
< beans::NamedValue
> aEncryptionData
;
5631 const SfxUnoAnyItem
* pEncryptionData
= SfxItemSet::GetItem
<SfxUnoAnyItem
>(rMedium
.GetItemSet(), SID_ENCRYPTIONDATA
, false);
5632 if ( pEncryptionData
&& ( pEncryptionData
->GetValue() >>= aEncryptionData
) && !rCodec
.InitCodec( aEncryptionData
) )
5633 aEncryptionData
.realloc( 0 );
5635 if ( !aEncryptionData
.hasElements() )
5637 OUString sUniPassword
= QueryPasswordForMedium( rMedium
);
5639 sal_Int32 nLen
= sUniPassword
.getLength();
5642 sal_uInt16 pPassword
[16];
5643 memset( pPassword
, 0, sizeof( pPassword
) );
5644 for( sal_Int32 nChar
= 0; nChar
< nLen
; ++nChar
)
5645 pPassword
[nChar
] = sUniPassword
[nChar
];
5647 rCodec
.InitKey( pPassword
, pDocId
);
5648 aEncryptionData
= rCodec
.GetEncryptionData();
5652 return aEncryptionData
;
5656 //TO-DO: merge this with lclReadFilepass8_Strong in sc which uses a different
5658 static bool lclReadCryptoAPIHeader(msfilter::RC4EncryptionInfo
&info
, SvStream
&rStream
)
5660 //It is possible there are other variants in existence but these
5661 //are the defaults I get with Word 2013
5663 rStream
.ReadUInt32(info
.header
.flags
);
5664 if (oox::getFlag( info
.header
.flags
, msfilter::ENCRYPTINFO_EXTERNAL
))
5667 sal_uInt32
nHeaderSize(0);
5668 rStream
.ReadUInt32(nHeaderSize
);
5669 sal_uInt32 actualHeaderSize
= sizeof(info
.header
);
5671 if (nHeaderSize
< actualHeaderSize
)
5674 rStream
.ReadUInt32(info
.header
.flags
);
5675 rStream
.ReadUInt32(info
.header
.sizeExtra
);
5676 rStream
.ReadUInt32(info
.header
.algId
);
5677 rStream
.ReadUInt32(info
.header
.algIdHash
);
5678 rStream
.ReadUInt32(info
.header
.keyBits
);
5679 rStream
.ReadUInt32(info
.header
.providedType
);
5680 rStream
.ReadUInt32(info
.header
.reserved1
);
5681 rStream
.ReadUInt32(info
.header
.reserved2
);
5683 rStream
.SeekRel(nHeaderSize
- actualHeaderSize
);
5685 rStream
.ReadUInt32(info
.verifier
.saltSize
);
5686 if (info
.verifier
.saltSize
!= msfilter::SALT_LENGTH
)
5688 rStream
.ReadBytes(&info
.verifier
.salt
, sizeof(info
.verifier
.salt
));
5689 rStream
.ReadBytes(&info
.verifier
.encryptedVerifier
, sizeof(info
.verifier
.encryptedVerifier
));
5691 rStream
.ReadUInt32(info
.verifier
.encryptedVerifierHashSize
);
5692 if (info
.verifier
.encryptedVerifierHashSize
!= RTL_DIGEST_LENGTH_SHA1
)
5694 rStream
.ReadBytes(&info
.verifier
.encryptedVerifierHash
, info
.verifier
.encryptedVerifierHashSize
);
5696 // check flags and algorithm IDs, required are AES128 and SHA-1
5697 if (!oox::getFlag(info
.header
.flags
, msfilter::ENCRYPTINFO_CRYPTOAPI
))
5700 if (oox::getFlag(info
.header
.flags
, msfilter::ENCRYPTINFO_AES
))
5703 if (info
.header
.algId
!= msfilter::ENCRYPT_ALGO_RC4
)
5706 // hash algorithm ID 0 defaults to SHA-1 too
5707 if (info
.header
.algIdHash
!= 0 && info
.header
.algIdHash
!= msfilter::ENCRYPT_HASH_SHA1
)
5713 ErrCode
SwWW8ImplReader::LoadThroughDecryption(WW8Glossary
*pGloss
)
5715 ErrCode nErrRet
= ERRCODE_NONE
;
5717 m_xWwFib
= pGloss
->GetFib();
5719 m_xWwFib
.reset(new WW8Fib(*m_pStrm
, m_nWantedVersion
));
5721 if (m_xWwFib
->m_nFibError
)
5722 nErrRet
= ERR_SWG_READ_ERROR
;
5724 tools::SvRef
<SotStorageStream
> xTableStream
, xDataStream
;
5727 nErrRet
= SetSubStreams(xTableStream
, xDataStream
);
5729 std::unique_ptr
<utl::TempFile
> pTempMain
;
5730 std::unique_ptr
<utl::TempFile
> pTempTable
;
5731 std::unique_ptr
<utl::TempFile
> pTempData
;
5732 SvFileStream aDecryptMain
;
5733 SvFileStream aDecryptTable
;
5734 SvFileStream aDecryptData
;
5736 bool bDecrypt
= false;
5737 enum {RC4CryptoAPI
, RC4
, XOR
, Other
} eAlgo
= Other
;
5738 if (m_xWwFib
->m_fEncrypted
&& !nErrRet
)
5743 if (8 != m_xWwFib
->m_nVersion
)
5747 if (m_xWwFib
->m_nKey
!= 0)
5751 m_pTableStream
->Seek(0);
5752 sal_uInt32
nEncType(0);
5753 m_pTableStream
->ReadUInt32(nEncType
);
5754 if (nEncType
== msfilter::VERSION_INFO_1997_FORMAT
)
5756 else if (nEncType
== msfilter::VERSION_INFO_2007_FORMAT
|| nEncType
== msfilter::VERSION_INFO_2007_FORMAT_SP2
)
5757 eAlgo
= RC4CryptoAPI
;
5765 nErrRet
= ERRCODE_SVX_WRONGPASS
;
5766 SfxMedium
* pMedium
= m_pDocShell
->GetMedium();
5773 nErrRet
= ERRCODE_SVX_READ_FILTER_CRYPT
;
5777 msfilter::MSCodec_XorWord95 aCtx
;
5778 uno::Sequence
< beans::NamedValue
> aEncryptionData
= InitXorWord95Codec(aCtx
, *pMedium
, m_xWwFib
.get());
5780 // if initialization has failed the EncryptionData should be empty
5781 if (aEncryptionData
.hasElements() && aCtx
.VerifyKey(m_xWwFib
->m_nKey
, m_xWwFib
->m_nHash
))
5783 nErrRet
= ERRCODE_NONE
;
5784 pTempMain
= MakeTemp(aDecryptMain
);
5787 size_t nUnencryptedHdr
=
5788 (8 == m_xWwFib
->m_nVersion
) ? 0x44 : 0x34;
5789 std::unique_ptr
<sal_uInt8
[]> pIn(new sal_uInt8
[nUnencryptedHdr
]);
5790 nUnencryptedHdr
= m_pStrm
->ReadBytes(pIn
.get(), nUnencryptedHdr
);
5791 aDecryptMain
.WriteBytes(pIn
.get(), nUnencryptedHdr
);
5794 DecryptXOR(aCtx
, *m_pStrm
, aDecryptMain
);
5796 if (!m_pTableStream
|| m_pTableStream
== m_pStrm
)
5797 m_pTableStream
= &aDecryptMain
;
5800 pTempTable
= MakeTemp(aDecryptTable
);
5801 DecryptXOR(aCtx
, *m_pTableStream
, aDecryptTable
);
5802 m_pTableStream
= &aDecryptTable
;
5805 if (!m_pDataStream
|| m_pDataStream
== m_pStrm
)
5806 m_pDataStream
= &aDecryptMain
;
5809 pTempData
= MakeTemp(aDecryptData
);
5810 DecryptXOR(aCtx
, *m_pDataStream
, aDecryptData
);
5811 m_pDataStream
= &aDecryptData
;
5814 pMedium
->GetItemSet()->ClearItem( SID_PASSWORD
);
5815 pMedium
->GetItemSet()->Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA
, uno::makeAny( aEncryptionData
) ) );
5822 std::unique_ptr
<msfilter::MSCodec97
> xCtx
;
5823 msfilter::RC4EncryptionInfo info
;
5824 bool bCouldReadHeaders
;
5828 xCtx
.reset(new msfilter::MSCodec_Std97
);
5829 assert(sizeof(info
.verifier
.encryptedVerifierHash
) >= RTL_DIGEST_LENGTH_MD5
);
5831 checkRead(*m_pTableStream
, info
.verifier
.salt
, sizeof(info
.verifier
.salt
)) &&
5832 checkRead(*m_pTableStream
, info
.verifier
.encryptedVerifier
, sizeof(info
.verifier
.encryptedVerifier
)) &&
5833 checkRead(*m_pTableStream
, info
.verifier
.encryptedVerifierHash
, RTL_DIGEST_LENGTH_MD5
);
5837 xCtx
.reset(new msfilter::MSCodec_CryptoAPI
);
5838 bCouldReadHeaders
= lclReadCryptoAPIHeader(info
, *m_pTableStream
);
5841 // if initialization has failed the EncryptionData should be empty
5842 uno::Sequence
< beans::NamedValue
> aEncryptionData
;
5843 if (bCouldReadHeaders
)
5844 aEncryptionData
= Init97Codec(*xCtx
, info
.verifier
.salt
, *pMedium
);
5846 nErrRet
= ERRCODE_SVX_READ_FILTER_CRYPT
;
5847 if (aEncryptionData
.hasElements() && xCtx
->VerifyKey(info
.verifier
.encryptedVerifier
,
5848 info
.verifier
.encryptedVerifierHash
))
5850 nErrRet
= ERRCODE_NONE
;
5852 pTempMain
= MakeTemp(aDecryptMain
);
5855 std::size_t nUnencryptedHdr
= 0x44;
5856 std::unique_ptr
<sal_uInt8
[]> pIn(new sal_uInt8
[nUnencryptedHdr
]);
5857 nUnencryptedHdr
= m_pStrm
->ReadBytes(pIn
.get(), nUnencryptedHdr
);
5859 DecryptRC4(*xCtx
, *m_pStrm
, aDecryptMain
);
5861 aDecryptMain
.Seek(0);
5862 aDecryptMain
.WriteBytes(pIn
.get(), nUnencryptedHdr
);
5865 pTempTable
= MakeTemp(aDecryptTable
);
5866 DecryptRC4(*xCtx
, *m_pTableStream
, aDecryptTable
);
5867 m_pTableStream
= &aDecryptTable
;
5869 if (!m_pDataStream
|| m_pDataStream
== m_pStrm
)
5870 m_pDataStream
= &aDecryptMain
;
5873 pTempData
= MakeTemp(aDecryptData
);
5874 DecryptRC4(*xCtx
, *m_pDataStream
, aDecryptData
);
5875 m_pDataStream
= &aDecryptData
;
5878 pMedium
->GetItemSet()->ClearItem( SID_PASSWORD
);
5879 pMedium
->GetItemSet()->Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA
, uno::makeAny( aEncryptionData
) ) );
5886 if (nErrRet
== ERRCODE_NONE
)
5888 m_pStrm
= &aDecryptMain
;
5890 m_xWwFib
.reset(new WW8Fib(*m_pStrm
, m_nWantedVersion
));
5891 if (m_xWwFib
->m_nFibError
)
5892 nErrRet
= ERR_SWG_READ_ERROR
;
5897 nErrRet
= CoreLoad(pGloss
);
5907 void SwWW8ImplReader::SetOutlineStyles()
5909 // If we are inserted into a document then don't clobber existing outline
5911 sal_uInt16 nOutlineStyleListLevelWithAssignment
= 0;
5914 ww8::ParaStyles
aOutLined(sw::util::GetParaStyles(m_rDoc
));
5915 sw::util::SortByAssignedOutlineStyleListLevel(aOutLined
);
5916 ww8::ParaStyles::reverse_iterator aEnd
= aOutLined
.rend();
5917 for ( ww8::ParaStyles::reverse_iterator aIter
= aOutLined
.rbegin(); aIter
< aEnd
; ++aIter
)
5919 if ((*aIter
)->IsAssignedToListLevelOfOutlineStyle())
5920 nOutlineStyleListLevelWithAssignment
|= 1 << (*aIter
)->GetAssignedOutlineStyleLevel();
5926 // Check applied WW8 list styles at WW8 Built-In Heading Styles
5927 // - Choose the list style which occurs most often as the one which provides
5928 // the list level properties for the Outline Style.
5929 // - Populate temporary list of WW8 Built-In Heading Styles for further
5931 std::vector
<SwWW8StyInf
*> aWW8BuiltInHeadingStyles
;
5932 const SwNumRule
* pChosenWW8ListStyle
= nullptr;
5934 std::map
<const SwNumRule
*, int> aWW8ListStyleCounts
;
5935 for (SwWW8StyInf
& rSI
: m_vColl
)
5937 if (!rSI
.IsWW8BuiltInHeadingStyle() || !rSI
.HasWW8OutlineLevel())
5942 aWW8BuiltInHeadingStyles
.push_back(&rSI
);
5944 const SwNumRule
* pWW8ListStyle
= rSI
.GetOutlineNumrule();
5945 if (pWW8ListStyle
!= nullptr)
5947 std::map
<const SwNumRule
*, int>::iterator aCountIter
5948 = aWW8ListStyleCounts
.find(pWW8ListStyle
);
5949 if (aCountIter
== aWW8ListStyleCounts
.end())
5951 aWW8ListStyleCounts
[pWW8ListStyle
] = 1;
5955 ++(aCountIter
->second
);
5960 int nCurrentMaxCount
= 0;
5961 for (const auto& rEntry
: aWW8ListStyleCounts
)
5963 if (rEntry
.second
> nCurrentMaxCount
)
5965 nCurrentMaxCount
= rEntry
.second
;
5966 pChosenWW8ListStyle
= rEntry
.first
;
5971 // - set list level properties of Outline Style - ODF's list style applied
5972 // by default to headings
5973 // - assign corresponding Heading Paragraph Styles to the Outline Style
5974 // - If a heading Paragraph Styles is not applying the WW8 list style which
5975 // had been chosen as
5976 // the one which provides the list level properties for the Outline Style,
5977 // its assignment to
5978 // the Outline Style is removed. A potential applied WW8 list style is
5979 // assigned directly and
5980 // its default outline level is applied.
5981 SwNumRule
aOutlineRule(*m_rDoc
.GetOutlineNumRule());
5982 bool bAppliedChangedOutlineStyle
= false;
5983 for (const SwWW8StyInf
* pStyleInf
: aWW8BuiltInHeadingStyles
)
5985 if (!pStyleInf
->m_bColl
) //Character Style
5988 const sal_uInt16 nOutlineStyleListLevelOfWW8BuiltInHeadingStyle
5989 = 1 << pStyleInf
->mnWW8OutlineLevel
;
5990 if (nOutlineStyleListLevelOfWW8BuiltInHeadingStyle
5991 & nOutlineStyleListLevelWithAssignment
)
5996 if (pChosenWW8ListStyle
!= nullptr && pStyleInf
->mnWW8OutlineLevel
5997 == pStyleInf
->m_nListLevel
)
5999 const SwNumFormat
& rRule
6000 = pChosenWW8ListStyle
->Get(pStyleInf
->mnWW8OutlineLevel
);
6001 aOutlineRule
.Set(pStyleInf
->mnWW8OutlineLevel
, rRule
);
6002 bAppliedChangedOutlineStyle
= true;
6005 // in case that there are more styles on this level ignore them
6006 nOutlineStyleListLevelWithAssignment
6007 |= nOutlineStyleListLevelOfWW8BuiltInHeadingStyle
;
6009 SwTextFormatColl
* pTextFormatColl
= static_cast<SwTextFormatColl
*>(pStyleInf
->m_pFormat
);
6010 if (pStyleInf
->GetOutlineNumrule() != pChosenWW8ListStyle
6011 || (pStyleInf
->m_nListLevel
< WW8ListManager::nMaxLevel
6012 && pStyleInf
->mnWW8OutlineLevel
!= pStyleInf
->m_nListLevel
))
6014 // WW8 Built-In Heading Style does not apply the chosen one.
6015 // --> delete assignment to OutlineStyle, but keep its current
6017 pTextFormatColl
->DeleteAssignmentToListLevelOfOutlineStyle();
6018 // Apply existing WW8 list style a normal list style at the
6020 if (pStyleInf
->GetOutlineNumrule() != nullptr)
6022 pTextFormatColl
->SetFormatAttr(
6023 SwNumRuleItem(pStyleInf
->GetOutlineNumrule()->GetName()));
6025 // apply default outline level of WW8 Built-in Heading Style
6026 const sal_uInt8 nOutlineLevel
6027 = SwWW8StyInf::WW8OutlineLevelToOutlinelevel(
6028 pStyleInf
->mnWW8OutlineLevel
);
6029 pTextFormatColl
->SetFormatAttr(
6030 SfxUInt16Item(RES_PARATR_OUTLINELEVEL
, nOutlineLevel
));
6034 pTextFormatColl
->AssignToListLevelOfOutlineStyle(
6035 pStyleInf
->mnWW8OutlineLevel
);
6039 if (bAppliedChangedOutlineStyle
)
6041 m_rDoc
.SetOutlineNumRule(aOutlineRule
);
6045 const OUString
* SwWW8ImplReader::GetAnnotationAuthor(sal_uInt16 nIdx
)
6047 if (!m_pAtnNames
&& m_xWwFib
->m_lcbGrpStAtnOwners
)
6049 // Determine authors: can be found in the TableStream
6050 m_pAtnNames
.reset(new std::vector
<OUString
>);
6051 SvStream
& rStrm
= *m_pTableStream
;
6053 long nOldPos
= rStrm
.Tell();
6054 rStrm
.Seek( m_xWwFib
->m_fcGrpStAtnOwners
);
6056 long nRead
= 0, nCount
= m_xWwFib
->m_lcbGrpStAtnOwners
;
6057 while (nRead
< nCount
&& rStrm
.good())
6061 m_pAtnNames
->push_back(read_uInt8_PascalString(rStrm
,
6062 RTL_TEXTENCODING_MS_1252
));
6063 nRead
+= m_pAtnNames
->rbegin()->getLength() + 1; // Length + sal_uInt8 count
6067 m_pAtnNames
->push_back(read_uInt16_PascalString(rStrm
));
6068 // Unicode: double the length + sal_uInt16 count
6069 nRead
+= (m_pAtnNames
->rbegin()->getLength() + 1)*2;
6072 rStrm
.Seek( nOldPos
);
6075 const OUString
*pRet
= nullptr;
6076 if (m_pAtnNames
&& nIdx
< m_pAtnNames
->size())
6077 pRet
= &((*m_pAtnNames
)[nIdx
]);
6081 void SwWW8ImplReader::GetSmartTagInfo(SwFltRDFMark
& rMark
)
6083 if (!m_pSmartTagData
&& m_xWwFib
->m_lcbFactoidData
)
6085 m_pSmartTagData
.reset(new WW8SmartTagData
);
6086 m_pSmartTagData
->Read(*m_pTableStream
, m_xWwFib
->m_fcFactoidData
, m_xWwFib
->m_lcbFactoidData
);
6089 if (!m_pSmartTagData
)
6092 // Check if the handle is a valid smart tag bookmark index.
6093 size_t nIndex
= rMark
.GetHandle();
6094 if (nIndex
>= m_pSmartTagData
->m_aPropBags
.size())
6097 // Check if the smart tag bookmark refers to a valid factoid type.
6098 const MSOPropertyBag
& rPropertyBag
= m_pSmartTagData
->m_aPropBags
[rMark
.GetHandle()];
6099 auto& rFactoidTypes
= m_pSmartTagData
->m_aPropBagStore
.m_aFactoidTypes
;
6100 auto itPropertyBag
= std::find_if(rFactoidTypes
.begin(), rFactoidTypes
.end(),
6101 [&rPropertyBag
](const MSOFactoidType
& rType
) { return rType
.m_nId
== rPropertyBag
.m_nId
; });
6102 if (itPropertyBag
== rFactoidTypes
.end())
6105 // Check if the factoid is an RDF one.
6106 const MSOFactoidType
& rFactoidType
= *itPropertyBag
;
6107 if (rFactoidType
.m_aUri
!= "http://www.w3.org/1999/02/22-rdf-syntax-ns#")
6110 // Finally put the relevant attributes to the mark.
6111 std::vector
< std::pair
<OUString
, OUString
> > aAttributes
;
6112 for (const MSOProperty
& rProperty
: rPropertyBag
.m_aProperties
)
6116 if (rProperty
.m_nKey
< m_pSmartTagData
->m_aPropBagStore
.m_aStringTable
.size())
6117 aKey
= m_pSmartTagData
->m_aPropBagStore
.m_aStringTable
[rProperty
.m_nKey
];
6118 if (rProperty
.m_nValue
< m_pSmartTagData
->m_aPropBagStore
.m_aStringTable
.size())
6119 aValue
= m_pSmartTagData
->m_aPropBagStore
.m_aStringTable
[rProperty
.m_nValue
];
6120 if (!aKey
.isEmpty() && !aValue
.isEmpty())
6121 aAttributes
.emplace_back(aKey
, aValue
);
6123 rMark
.SetAttributes(aAttributes
);
6126 ErrCode
SwWW8ImplReader::LoadDoc(WW8Glossary
*pGloss
)
6128 ErrCode nErrRet
= ERRCODE_NONE
;
6131 static const sal_Char
* aNames
[ 13 ] = {
6132 "WinWord/WW", "WinWord/WW8", "WinWord/WWFT",
6133 "WinWord/WWFLX", "WinWord/WWFLY",
6135 "WinWord/WWFA0", "WinWord/WWFA1", "WinWord/WWFA2",
6136 "WinWord/WWFB0", "WinWord/WWFB1", "WinWord/WWFB2",
6137 "WinWord/RegardHindiDigits"
6139 sal_uInt64 aVal
[ 13 ];
6141 SwFilterOptions
aOpt( 13, aNames
, aVal
);
6143 m_nIniFlags
= aVal
[ 0 ];
6144 m_nIniFlags1
= aVal
[ 1 ];
6145 // Moves Flys by x twips to the right or left
6146 m_nIniFlyDx
= aVal
[ 3 ];
6147 m_nIniFlyDy
= aVal
[ 4 ];
6149 m_nFieldFlags
= aVal
[ 5 ];
6150 m_nFieldTagAlways
[0] = aVal
[ 6 ];
6151 m_nFieldTagAlways
[1] = aVal
[ 7 ];
6152 m_nFieldTagAlways
[2] = aVal
[ 8 ];
6153 m_nFieldTagBad
[0] = aVal
[ 9 ];
6154 m_nFieldTagBad
[1] = aVal
[ 10 ];
6155 m_nFieldTagBad
[2] = aVal
[ 11 ];
6156 m_bRegardHindiDigits
= aVal
[ 12 ] > 0;
6159 sal_uInt16
nMagic(0);
6160 m_pStrm
->ReadUInt16( nMagic
);
6162 // Remember: 6 means "6 OR 7", 7 means "JUST 7"
6163 switch (m_nWantedVersion
)
6168 0xa59b != nMagic
&& 0xa59c != nMagic
&&
6169 0xa5dc != nMagic
&& 0xa5db != nMagic
&&
6170 (nMagic
< 0xa697 || nMagic
> 0xa699)
6173 // Test for own 97 fake!
6174 if (m_pStg
&& 0xa5ec == nMagic
)
6176 sal_uLong nCurPos
= m_pStrm
->Tell();
6177 if (m_pStrm
->Seek(nCurPos
+ 22))
6180 m_pStrm
->ReadUInt32( nfcMin
);
6181 if (0x300 != nfcMin
)
6182 nErrRet
= ERR_WW6_NO_WW6_FILE_ERR
;
6184 m_pStrm
->Seek( nCurPos
);
6187 nErrRet
= ERR_WW6_NO_WW6_FILE_ERR
;
6191 if (0xa5ec != nMagic
)
6192 nErrRet
= ERR_WW8_NO_WW8_FILE_ERR
;
6195 nErrRet
= ERR_WW8_NO_WW8_FILE_ERR
;
6196 OSL_ENSURE( false, "We forgot to encode nVersion!" );
6201 nErrRet
= LoadThroughDecryption(pGloss
);
6203 m_rDoc
.PropagateOutlineRule();
6208 extern "C" SAL_DLLPUBLIC_EXPORT Reader
* ImportDOC()
6210 return new WW8Reader
;
6215 class FontCacheGuard
6225 bool TestImportDOC(SvStream
&rStream
, const OUString
&rFltName
)
6227 FontCacheGuard aFontCacheGuard
;
6228 std::unique_ptr
<Reader
> xReader(ImportDOC());
6230 tools::SvRef
<SotStorage
> xStorage
;
6231 xReader
->m_pStream
= &rStream
;
6232 if (rFltName
!= "WW6")
6236 xStorage
= tools::SvRef
<SotStorage
>(new SotStorage(rStream
));
6237 if (xStorage
->GetError())
6244 xReader
->m_pStorage
= xStorage
.get();
6246 xReader
->SetFltName(rFltName
);
6248 SwGlobals::ensure();
6250 SfxObjectShellLock
xDocSh(new SwDocShell(SfxObjectCreateMode::INTERNAL
));
6251 xDocSh
->DoInitNew();
6252 SwDoc
*pD
= static_cast<SwDocShell
*>((&xDocSh
))->GetDoc();
6254 SwNodeIndex
aIdx(pD
->GetNodes().GetEndOfContent(), -1);
6256 aPaM
.GetPoint()->nContent
.Assign(aIdx
.GetNode().GetContentNode(), 0);
6257 pD
->SetInReading(true);
6258 bool bRet
= xReader
->Read(*pD
, OUString(), aPaM
, OUString()) == ERRCODE_NONE
;
6259 pD
->SetInReading(false);
6264 extern "C" SAL_DLLPUBLIC_EXPORT
bool TestImportWW8(SvStream
&rStream
)
6266 return TestImportDOC(rStream
, "CWW8");
6269 extern "C" SAL_DLLPUBLIC_EXPORT
bool TestImportWW6(SvStream
&rStream
)
6271 return TestImportDOC(rStream
, "CWW6");
6274 extern "C" SAL_DLLPUBLIC_EXPORT
bool TestImportWW2(SvStream
&rStream
)
6276 return TestImportDOC(rStream
, "WW6");
6279 ErrCode
WW8Reader::OpenMainStream( tools::SvRef
<SotStorageStream
>& rRef
, sal_uInt16
& rBuffSize
)
6281 ErrCode nRet
= ERR_SWG_READ_ERROR
;
6282 OSL_ENSURE(m_pStorage
, "Where is my Storage?");
6283 rRef
= m_pStorage
->OpenSotStream( "WordDocument", StreamMode::READ
| StreamMode::SHARE_DENYALL
);
6287 if( ERRCODE_NONE
== rRef
->GetError() )
6289 sal_uInt16 nOld
= rRef
->GetBufferSize();
6290 rRef
->SetBufferSize( rBuffSize
);
6292 nRet
= ERRCODE_NONE
;
6295 nRet
= rRef
->GetError();
6300 ErrCode
WW8Reader::Read(SwDoc
&rDoc
, const OUString
& rBaseURL
, SwPaM
&rPaM
, const OUString
& /* FileName */)
6302 sal_uInt16 nOldBuffSize
= 32768;
6303 bool bNew
= !m_bInsertMode
; // New Doc (no inserting)
6305 tools::SvRef
<SotStorageStream
> refStrm
; // So that no one else can steal the Stream
6306 SvStream
* pIn
= m_pStream
;
6308 ErrCode nRet
= ERRCODE_NONE
;
6309 sal_uInt8 nVersion
= 8;
6311 const OUString sFltName
= GetFltName();
6312 if ( sFltName
=="WW6" )
6318 OSL_ENSURE(false, "WinWord 95 Reader-Read without Stream");
6319 nRet
= ERR_SWG_READ_ERROR
;
6324 if ( sFltName
=="CWW6" )
6326 else if ( sFltName
=="CWW7" )
6329 if( m_pStorage
.is() )
6331 nRet
= OpenMainStream( refStrm
, nOldBuffSize
);
6332 pIn
= refStrm
.get();
6336 OSL_ENSURE(false, "WinWord 95/97 Reader-Read without Storage");
6337 nRet
= ERR_SWG_READ_ERROR
;
6343 std::unique_ptr
<SwWW8ImplReader
> pRdr(new SwWW8ImplReader(nVersion
, m_pStorage
.get(), pIn
, rDoc
,
6344 rBaseURL
, bNew
, m_bSkipImages
, *rPaM
.GetPoint()));
6347 rPaM
.GetBound().nContent
.Assign(nullptr, 0);
6348 rPaM
.GetBound(false).nContent
.Assign(nullptr, 0);
6352 nRet
= pRdr
->LoadDoc();
6354 catch( const std::exception
& )
6356 nRet
= ERR_WW8_NO_WW8_FILE_ERR
;
6361 refStrm
->SetBufferSize( nOldBuffSize
);
6373 SwReaderType
WW8Reader::GetReaderType()
6375 return SwReaderType::Storage
| SwReaderType::Stream
;
6378 bool WW8Reader::HasGlossaries() const
6383 bool WW8Reader::ReadGlossaries(SwTextBlocks
& rBlocks
, bool bSaveRelFiles
) const
6387 WW8Reader
*pThis
= const_cast<WW8Reader
*>(this);
6389 sal_uInt16 nOldBuffSize
= 32768;
6390 tools::SvRef
<SotStorageStream
> refStrm
;
6391 if (!pThis
->OpenMainStream(refStrm
, nOldBuffSize
))
6393 WW8Glossary
aGloss( refStrm
, 8, m_pStorage
.get() );
6394 bRet
= aGloss
.Load( rBlocks
, bSaveRelFiles
);
6399 bool SwMSDffManager::GetOLEStorageName(sal_uInt32 nOLEId
, OUString
& rStorageName
,
6400 tools::SvRef
<SotStorage
>& rSrcStorage
, uno::Reference
< embed::XStorage
>& rDestStorage
) const
6404 sal_Int32 nPictureId
= 0;
6407 // Via the TextBox-PLCF we get the right char Start-End positions
6408 // We should then find the EmbeddedField and the corresponding Sprms
6410 // We only need the Sprm for the Picture Id.
6411 long nOldPos
= rReader
.m_pStrm
->Tell();
6413 // #i32596# - consider return value of method
6414 // <rReader.GetTxbxTextSttEndCp(..)>. If it returns false, method
6415 // wasn't successful. Thus, continue in this case.
6416 // Note: Ask MM for initialization of <nStartCp> and <nEndCp>.
6417 // Note: Ask MM about assertions in method <rReader.GetTxbxTextSttEndCp(..)>.
6418 WW8_CP nStartCp
, nEndCp
;
6419 if ( rReader
.m_bDrawCpOValid
&& rReader
.GetTxbxTextSttEndCp(nStartCp
, nEndCp
,
6420 static_cast<sal_uInt16
>((nOLEId
>> 16) & 0xFFFF),
6421 static_cast<sal_uInt16
>(nOLEId
& 0xFFFF)) )
6423 WW8PLCFxSaveAll aSave
;
6424 rReader
.m_xPlcxMan
->SaveAllPLCFx( aSave
);
6426 nStartCp
+= rReader
.m_nDrawCpO
;
6427 nEndCp
+= rReader
.m_nDrawCpO
;
6428 WW8PLCFx_Cp_FKP
* pChp
= rReader
.m_xPlcxMan
->GetChpPLCF();
6429 wwSprmParser
aSprmParser(*rReader
.m_xWwFib
);
6430 while (nStartCp
<= nEndCp
&& !nPictureId
)
6432 if (!pChp
->SeekPos( nStartCp
))
6435 pChp
->GetSprms( &aDesc
);
6437 if (aDesc
.nSprmsLen
&& aDesc
.pMemPos
) // Attributes present
6439 long nLen
= aDesc
.nSprmsLen
;
6440 const sal_uInt8
* pSprm
= aDesc
.pMemPos
;
6442 while (nLen
>= 2 && !nPictureId
)
6444 sal_uInt16 nId
= aSprmParser
.GetSprmId(pSprm
);
6445 sal_uInt16 nSL
= aSprmParser
.GetSprmSize(nId
, pSprm
, nLen
);
6448 break; // Not enough Bytes left
6452 nPictureId
= SVBT32ToUInt32(pSprm
+
6453 aSprmParser
.DistanceToData(nId
));
6460 nStartCp
= aDesc
.nEndPos
;
6463 rReader
.m_xPlcxMan
->RestoreAllPLCFx( aSave
);
6466 rReader
.m_pStrm
->Seek( nOldPos
);
6472 rStorageName
+= OUString::number(nPictureId
);
6473 rSrcStorage
= rReader
.m_pStg
->OpenSotStorage(SL::aObjectPool
);
6474 if (!rReader
.m_pDocShell
)
6477 rDestStorage
= rReader
.m_pDocShell
->GetStorage();
6483 * When reading a single Box (which possibly is part of a group), we do
6484 * not yet have enough information to decide whether we need it as a TextField
6486 * So convert all of them as a precaution.
6487 * FIXME: Actually implement this!
6489 bool SwMSDffManager::ShapeHasText(sal_uLong
, sal_uLong
) const
6494 bool SwWW8ImplReader::InEqualOrHigherApo(int nLvl
) const
6498 // #i60827# - check size of <maApos> to assure that <maApos.begin() + nLvl> can be performed.
6499 if ( sal::static_int_cast
< sal_Int32
>(nLvl
) >= sal::static_int_cast
< sal_Int32
>(m_aApos
.size()) )
6503 auto aIter
= std::find(m_aApos
.begin() + nLvl
, m_aApos
.end(), true);
6504 return aIter
!= m_aApos
.end();
6507 bool SwWW8ImplReader::InEqualApo(int nLvl
) const
6509 // If we are in a table, see if an apo was inserted at the level below the table.
6512 if (nLvl
< 0 || static_cast<size_t>(nLvl
) >= m_aApos
.size())
6514 return m_aApos
[nLvl
];
6521 Position::Position(const SwPosition
&rPos
)
6522 : maPtNode(rPos
.nNode
), mnPtContent(rPos
.nContent
.GetIndex())
6526 Position::Position(const Position
&rPos
)
6527 : maPtNode(rPos
.maPtNode
), mnPtContent(rPos
.mnPtContent
)
6531 Position::operator SwPosition() const
6533 SwPosition
aRet(maPtNode
);
6534 aRet
.nContent
.Assign(maPtNode
.GetNode().GetContentNode(), mnPtContent
);
6540 SwMacroInfo::SwMacroInfo()
6541 : SdrObjUserData( SdrInventor::ScOrSwDraw
, SW_UD_IMAPDATA
)
6546 SwMacroInfo::~SwMacroInfo()
6550 std::unique_ptr
<SdrObjUserData
> SwMacroInfo::Clone( SdrObject
* /*pObj*/ ) const
6552 return std::unique_ptr
<SdrObjUserData
>(new SwMacroInfo( *this ));
6555 std::unique_ptr
<SfxItemSet
> SwWW8ImplReader::SetCurrentItemSet(std::unique_ptr
<SfxItemSet
> pItemSet
)
6557 std::unique_ptr
<SfxItemSet
> xRet(std::move(m_xCurrentItemSet
));
6558 m_xCurrentItemSet
= std::move(pItemSet
);
6562 void SwWW8ImplReader::NotifyMacroEventRead()
6564 if (m_bNotifyMacroEventRead
)
6566 uno::Reference
<frame::XModel
> const xModel(m_rDoc
.GetDocShell()->GetBaseModel());
6567 comphelper::DocumentInfo::notifyMacroEventRead(xModel
);
6568 m_bNotifyMacroEventRead
= true;
6571 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */