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 .
22 #include <comphelper/diagnose_ex.hxx>
23 #include <rtl/tencinfo.h>
24 #include <svl/itemiter.hxx>
25 #include <svl/whiter.hxx>
26 #include <svtools/rtftoken.h>
27 #include <svl/itempool.hxx>
28 #include <i18nlangtag/languagetag.hxx>
29 #include <tools/debug.hxx>
30 #include <unotools/configmgr.hxx>
32 #include <comphelper/string.hxx>
34 #include <editeng/scriptspaceitem.hxx>
35 #include <editeng/fontitem.hxx>
36 #include <editeng/svxrtf.hxx>
37 #include <editeng/editids.hrc>
38 #include <vcl/font.hxx>
39 #include <vcl/svapp.hxx>
40 #include <vcl/settings.hxx>
43 using namespace ::com::sun::star
;
46 static rtl_TextEncoding
lcl_GetDefaultTextEncodingForRTF()
49 OUString
aLangString( Application::GetSettings().GetLanguageTag().getLanguage());
51 if ( aLangString
== "ru" || aLangString
== "uk" )
52 return RTL_TEXTENCODING_MS_1251
;
53 if ( aLangString
== "tr" )
54 return RTL_TEXTENCODING_MS_1254
;
56 return RTL_TEXTENCODING_MS_1252
;
59 // -------------- Methods --------------------
61 SvxRTFParser::SvxRTFParser( SfxItemPool
& rPool
, SvStream
& rIn
)
62 : SvRTFParser( rIn
, 5 )
67 , bIsSetDfltTab( false)
68 , bChkStyleAttr( false )
70 , bIsLeftToRightDef( true)
71 , bIsInReadStyleTab( false)
74 mxDefaultColor
= Color();
76 // generate the correct WhichId table from the set WhichIds.
80 SvxRTFParser::~SvxRTFParser()
82 if( !aAttrStack
.empty() )
86 void SvxRTFParser::SetInsPos( const EditPosition
& rNew
)
88 mxInsertPosition
= rNew
;
91 SvParserState
SvxRTFParser::CallParser()
93 DBG_ASSERT( mxInsertPosition
, "no insertion position");
95 if( !mxInsertPosition
)
96 return SvParserState::Error
;
98 if( !maColorTable
.empty() )
101 m_StyleTable
.clear();
102 if( !aAttrStack
.empty() )
105 bIsSetDfltTab
= false;
109 return SvRTFParser::CallParser();
112 void SvxRTFParser::Continue( int nToken
)
114 SvRTFParser::Continue( nToken
);
116 SvParserState eStatus
= GetStatus();
117 if (eStatus
!= SvParserState::Pending
&& eStatus
!= SvParserState::Error
)
120 //Regardless of what "color 0" is, word defaults to auto as the default colour.
126 // is called for each token that is recognized in CallParser
127 void SvxRTFParser::NextToken( int nToken
)
132 case RTF_COLORTBL
: ReadColorTable(); break;
133 case RTF_FONTTBL
: ReadFontTable(); break;
134 case RTF_STYLESHEET
: ReadStyleTable(); break;
139 if (!m_FontTable
.empty())
140 // Can immediately be set
141 SetDefault( nToken
, nTokenValue
);
143 // is set after reading the font table
144 nDfltFont
= int(nTokenValue
);
151 SetDefault( nToken
, nTokenValue
);
155 case RTF_PICT
: ReadBitmapData(); break;
157 case RTF_LINE
: cCh
= '\n'; goto INSINGLECHAR
;
158 case RTF_TAB
: cCh
= '\t'; goto INSINGLECHAR
;
159 case RTF_SUBENTRYINDEX
: cCh
= ':'; goto INSINGLECHAR
;
161 case RTF_EMDASH
: cCh
= 0x2014; goto INSINGLECHAR
;
162 case RTF_ENDASH
: cCh
= 0x2013; goto INSINGLECHAR
;
163 case RTF_BULLET
: cCh
= 0x2022; goto INSINGLECHAR
;
164 case RTF_LQUOTE
: cCh
= 0x2018; goto INSINGLECHAR
;
165 case RTF_RQUOTE
: cCh
= 0x2019; goto INSINGLECHAR
;
166 case RTF_LDBLQUOTE
: cCh
= 0x201C; goto INSINGLECHAR
;
167 case RTF_RDBLQUOTE
: cCh
= 0x201D; goto INSINGLECHAR
;
169 aToken
= OUStringChar(cCh
);
170 [[fallthrough
]]; // aToken is set as Text
174 // all collected Attributes are set
175 for (size_t n
= m_AttrSetList
.size(); n
; )
177 auto const& pStkSet
= m_AttrSetList
[--n
];
178 SetAttrSet( *pStkSet
);
179 m_AttrSetList
.pop_back();
189 if (bNewGroup
) // Nesting!
194 if( !bNewGroup
) // Empty Group ??
202 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
203 // First overwrite all (all have to be in one group!!)
204 // Could also appear in the RTF-file without the IGNORE-Flag; all Groups
205 // with the IGNORE-Flag are overwritten in the default branch.
207 case RTF_SWG_PRTDATA
:
219 // RTF_SHPRSLT disabled for #i19718#
222 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
227 if( RTF_IGNOREFLAG
!= GetStackPtr( -1 )->nTokenId
)
229 nToken
= SkipToken();
230 if( '{' == GetStackPtr( -1 )->nTokenId
)
231 nToken
= SkipToken();
233 ReadAttr( nToken
, &GetAttrSet() );
237 switch( nToken
& ~(0xff | RTF_SWGDEFS
) )
239 case RTF_PARFMT
: // here are no SWGDEFS
240 ReadAttr( nToken
, &GetAttrSet() );
247 if( RTF_SWGDEFS
& nToken
)
249 if( RTF_IGNOREFLAG
!= GetStackPtr( -1 )->nTokenId
)
251 nToken
= SkipToken();
252 if( '{' == GetStackPtr( -1 )->nTokenId
)
254 nToken
= SkipToken();
257 ReadAttr( nToken
, &GetAttrSet() );
261 if( RTF_IGNOREFLAG
== GetStackPtr( -1 )->nTokenId
&&
262 '{' == GetStackPtr( -2 )->nTokenId
)
271 void SvxRTFParser::ReadStyleTable()
273 int bSaveChkStyleAttr
= bChkStyleAttr
? 1 : 0;
274 sal_uInt16 nStyleNo
= 0;
275 bool bHasStyleNo
= false;
276 int _nOpenBrackets
= 1; // the first was already detected earlier!!
277 std::optional
<SvxRTFStyleType
> xStyle(SvxRTFStyleType(*pAttrPool
, aWhichMap
));
278 xStyle
->aAttrSet
.Put( GetRTFDefaults() );
280 bIsInReadStyleTab
= true;
281 bChkStyleAttr
= false; // Do not check Attribute against the Styles
283 while( _nOpenBrackets
&& IsParserWorking() )
285 int nToken
= GetNextToken();
288 case '}': if( --_nOpenBrackets
&& IsParserWorking() )
289 // Style has been completely read,
290 // so this is still a stable status
291 SaveState( RTF_STYLESHEET
);
295 if( RTF_IGNOREFLAG
!= GetNextToken() )
297 else if( RTF_UNKNOWNCONTROL
!= ( nToken
= GetNextToken() ) &&
302 // filter out at once
304 nToken
= GetNextToken();
306 eState
= SvParserState::Error
;
313 case RTF_SBASEDON
: xStyle
->nBasedOn
= sal_uInt16(nTokenValue
); break;
314 case RTF_SNEXT
: break;
315 case RTF_OUTLINELEVEL
:
316 case RTF_SOUTLVL
: xStyle
->nOutlineNo
= sal_uInt8(nTokenValue
); break;
317 case RTF_S
: nStyleNo
= static_cast<short>(nTokenValue
);
320 case RTF_CS
: nStyleNo
= static_cast<short>(nTokenValue
);
327 DelCharAtEnd( aToken
, ';' );
328 xStyle
->sName
= aToken
.toString();
330 if (!m_StyleTable
.empty())
332 m_StyleTable
.erase(nStyleNo
);
334 // All data from the font is available, so off to the table
335 m_StyleTable
.emplace(nStyleNo
, std::move(*xStyle
));
336 xStyle
.emplace(*pAttrPool
, aWhichMap
);
337 xStyle
->aAttrSet
.Put( GetRTFDefaults() );
343 switch( nToken
& ~(0xff | RTF_SWGDEFS
) )
345 case RTF_PARFMT
: // here are no SWGDEFS
346 ReadAttr( nToken
, &xStyle
->aAttrSet
);
353 auto nEnteringToken
= nToken
;
355 auto nEnteringIndex
= m_nTokenIndex
;
356 int nSkippedTokens
= 0;
357 if( RTF_SWGDEFS
& nToken
)
359 if( RTF_IGNOREFLAG
!= GetStackPtr( -1 )->nTokenId
)
361 nToken
= SkipToken();
363 if( '{' == GetStackPtr( -1 )->nTokenId
)
365 nToken
= SkipToken();
369 ReadAttr( nToken
, &xStyle
->aAttrSet
);
370 if (nSkippedTokens
&& m_nTokenIndex
== nEnteringIndex
- nSkippedTokens
)
372 // we called SkipToken to go back one or two, but ReadAttrs
373 // read nothing, so on next loop of the outer while we
374 // would end up in the same state again (assert that)
375 assert(nEnteringToken
== GetNextToken());
376 // and loop endlessly, skip format a token
377 // instead to avoid that
378 SkipToken(nSkippedTokens
);
385 xStyle
.reset(); // Delete the Last Style
386 SkipToken(); // the closing brace is evaluated "above"
388 // Flag back to old state
389 bChkStyleAttr
= bSaveChkStyleAttr
;
390 bIsInReadStyleTab
= false;
393 void SvxRTFParser::ReadColorTable()
396 sal_uInt8 nRed
= 0xff, nGreen
= 0xff, nBlue
= 0xff;
400 nToken
= GetNextToken();
401 if ( '}' == nToken
|| !IsParserWorking() )
405 case RTF_RED
: nRed
= sal_uInt8(nTokenValue
); break;
406 case RTF_GREEN
: nGreen
= sal_uInt8(nTokenValue
); break;
407 case RTF_BLUE
: nBlue
= sal_uInt8(nTokenValue
); break;
410 if( 1 == aToken
.getLength()
412 : -1 == aToken
.indexOf( ";" ) )
413 break; // At least the ';' must be found
418 if( IsParserWorking() )
420 // one color is finished, fill in the table
421 // try to map the values to SV internal names
422 Color
aColor( nRed
, nGreen
, nBlue
);
423 if( maColorTable
.empty() &&
424 sal_uInt8(-1) == nRed
&& sal_uInt8(-1) == nGreen
&& sal_uInt8(-1) == nBlue
)
426 maColorTable
.push_back( aColor
);
431 // Color has been completely read,
432 // so this is still a stable status
433 SaveState( RTF_COLORTBL
);
438 SkipToken(); // the closing brace is evaluated "above"
441 void SvxRTFParser::ReadFontTable()
443 int _nOpenBrackets
= 1; // the first was already detected earlier!!
445 short nFontNo(0), nInsFontNo (0);
446 OUString sAltNm
, sFntNm
;
447 bool bIsAltFntNm
= false;
449 rtl_TextEncoding nSystemChar
= lcl_GetDefaultTextEncodingForRTF();
450 aFont
.SetCharSet( nSystemChar
);
451 SetEncoding( nSystemChar
);
453 while( _nOpenBrackets
&& IsParserWorking() )
455 bool bCheckNewFont
= false;
456 int nToken
= GetNextToken();
461 // Style has been completely read,
462 // so this is still a stable status
463 if( --_nOpenBrackets
<= 1 && IsParserWorking() )
464 SaveState( RTF_FONTTBL
);
465 bCheckNewFont
= true;
466 nInsFontNo
= nFontNo
;
469 if( RTF_IGNOREFLAG
!= GetNextToken() )
471 // immediately skip unknown and all known but non-evaluated
473 else if( RTF_UNKNOWNCONTROL
!= ( nToken
= GetNextToken() ) &&
474 RTF_PANOSE
!= nToken
&& RTF_FNAME
!= nToken
&&
475 RTF_FONTEMB
!= nToken
&& RTF_FONTFILE
!= nToken
)
479 // filter out at once
481 nToken
= GetNextToken();
483 eState
= SvParserState::Error
;
489 aFont
.SetFamily( FAMILY_ROMAN
);
492 aFont
.SetFamily( FAMILY_SWISS
);
495 aFont
.SetFamily( FAMILY_MODERN
);
498 aFont
.SetFamily( FAMILY_SCRIPT
);
501 aFont
.SetFamily( FAMILY_DECORATIVE
);
503 // for technical/symbolic font of the rtl_TextEncoding is changed!
505 aFont
.SetCharSet( RTL_TEXTENCODING_SYMBOL
);
508 aFont
.SetFamily( FAMILY_DONTKNOW
);
511 if (-1 != nTokenValue
)
513 rtl_TextEncoding nrtl_TextEncoding
= rtl_getTextEncodingFromWindowsCharset(
514 static_cast<sal_uInt8
>(nTokenValue
));
515 aFont
.SetCharSet(nrtl_TextEncoding
);
516 //When we're in a font, the fontname is in the font
517 //charset, except for symbol fonts I believe
518 if (nrtl_TextEncoding
== RTL_TEXTENCODING_SYMBOL
)
519 nrtl_TextEncoding
= RTL_TEXTENCODING_DONTKNOW
;
520 SetEncoding(nrtl_TextEncoding
);
524 switch( nTokenValue
)
527 aFont
.SetPitch( PITCH_FIXED
);
530 aFont
.SetPitch( PITCH_VARIABLE
);
535 bCheckNewFont
= true;
536 nInsFontNo
= nFontNo
;
537 nFontNo
= static_cast<short>(nTokenValue
);
543 DelCharAtEnd( aToken
, ';' );
544 if ( !aToken
.isEmpty() )
554 if( bCheckNewFont
&& 1 >= _nOpenBrackets
&& !sFntNm
.isEmpty() ) // one font is ready
556 // All data from the font is available, so off to the table
557 if (!sAltNm
.isEmpty())
558 sFntNm
+= ";" + sAltNm
;
560 aFont
.SetFamilyName( sFntNm
);
561 m_FontTable
.insert(std::make_pair(nInsFontNo
, aFont
));
563 aFont
.SetCharSet( nSystemChar
);
568 SkipToken(); // the closing brace is evaluated "above"
570 // set the default font in the Document
571 if( bNewDoc
&& IsParserWorking() )
572 SetDefault( RTF_DEFF
, nDfltFont
);
575 void SvxRTFParser::ClearColorTbl()
577 maColorTable
.clear();
580 void SvxRTFParser::ClearAttrStack()
585 void SvxRTFParser::DelCharAtEnd( OUStringBuffer
& rStr
, const sal_Unicode cDel
)
588 if( !rStr
.isEmpty() && cDel
== rStr
[ rStr
.getLength()-1 ])
589 rStr
.setLength( rStr
.getLength()-1 );
593 const vcl::Font
& SvxRTFParser::GetFont( sal_uInt16 nId
)
595 SvxRTFFontTbl::const_iterator it
= m_FontTable
.find( nId
);
596 if (it
!= m_FontTable
.end())
600 const SvxFontItem
& rDfltFont
=
601 pAttrPool
->GetDefaultItem(aPlainMap
[SID_ATTR_CHAR_FONT
]);
602 pDfltFont
->SetFamilyName( rDfltFont
.GetStyleName() );
603 pDfltFont
->SetFamily( rDfltFont
.GetFamily() );
607 std::unique_ptr
<SvxRTFItemStackType
> SvxRTFItemStackType::createSvxRTFItemStackType(
608 SfxItemPool
& rPool
, const WhichRangesContainer
& pWhichRange
, const EditPosition
& rEditPosition
)
610 struct MakeUniqueEnabler
: public SvxRTFItemStackType
612 MakeUniqueEnabler(SfxItemPool
& rPool
, const WhichRangesContainer
& pWhichRange
, const EditPosition
& rEditPosition
)
613 : SvxRTFItemStackType(rPool
, pWhichRange
, rEditPosition
)
617 return std::make_unique
<MakeUniqueEnabler
>(rPool
, pWhichRange
, rEditPosition
);
620 SvxRTFItemStackType
* SvxRTFParser::GetAttrSet_()
622 SvxRTFItemStackType
* pCurrent
= aAttrStack
.empty() ? nullptr : aAttrStack
.back().get();
623 std::unique_ptr
<SvxRTFItemStackType
> xNew
;
625 xNew
= std::make_unique
<SvxRTFItemStackType
>(*pCurrent
, *mxInsertPosition
, false/*bCopyAttr*/);
627 xNew
= SvxRTFItemStackType::createSvxRTFItemStackType(*pAttrPool
, aWhichMap
, *mxInsertPosition
);
628 xNew
->SetRTFDefaults( GetRTFDefaults() );
630 aAttrStack
.push_back( std::move(xNew
) );
632 if (aAttrStack
.size() > 96 && utl::ConfigManager::IsFuzzing())
633 throw std::range_error("ecStackOverflow");
636 return aAttrStack
.back().get();
639 void SvxRTFParser::ClearStyleAttr_( SvxRTFItemStackType
& rStkType
)
641 // check attributes to the attributes of the stylesheet or to
642 // the default attrs of the document
643 SfxItemSet
&rSet
= rStkType
.GetAttrSet();
644 const SfxItemPool
& rPool
= *rSet
.GetPool();
645 const SfxPoolItem
* pItem
;
646 SfxWhichIter
aIter( rSet
);
648 if( !IsChkStyleAttr() ||
649 !rStkType
.GetAttrSet().Count() ||
650 m_StyleTable
.count( rStkType
.nStyleNo
) == 0 )
652 for( sal_uInt16 nWhich
= aIter
.GetCurWhich(); nWhich
; nWhich
= aIter
.NextWhich() )
654 if (SfxItemPool::IsWhich(nWhich
) &&
655 SfxItemState::SET
== aIter
.GetItemState( false, &pItem
) &&
656 rPool
.GetDefaultItem( nWhich
) == *pItem
)
657 aIter
.ClearItem(); // delete
662 // Delete all Attributes, which are already defined in the Style,
663 // from the current AttrSet.
664 auto & rStyle
= m_StyleTable
.find(rStkType
.nStyleNo
)->second
;
665 SfxItemSet
&rStyleSet
= rStyle
.aAttrSet
;
666 const SfxPoolItem
* pSItem
;
667 for( sal_uInt16 nWhich
= aIter
.GetCurWhich(); nWhich
; nWhich
= aIter
.NextWhich() )
669 if( SfxItemState::SET
== rStyleSet
.GetItemState( nWhich
, true, &pSItem
))
671 if( SfxItemState::SET
== aIter
.GetItemState( false, &pItem
)
672 && *pItem
== *pSItem
)
673 rSet
.ClearItem( nWhich
); // delete
675 else if (SfxItemPool::IsWhich(nWhich
) &&
676 SfxItemState::SET
== aIter
.GetItemState( false, &pItem
) &&
677 rPool
.GetDefaultItem( nWhich
) == *pItem
)
678 rSet
.ClearItem( nWhich
); // delete
683 void SvxRTFParser::AttrGroupEnd() // process the current, delete from Stack
685 if( aAttrStack
.empty() )
688 std::unique_ptr
<SvxRTFItemStackType
> pOld
= std::move(aAttrStack
.back());
689 aAttrStack
.pop_back();
690 SvxRTFItemStackType
*pCurrent
= aAttrStack
.empty() ? nullptr : aAttrStack
.back().get();
692 do { // middle check loop
693 sal_Int32 nOldSttNdIdx
= pOld
->mxStartNodeIdx
->GetIdx();
694 if (pOld
->maChildList
.empty() &&
695 ((!pOld
->aAttrSet
.Count() && !pOld
->nStyleNo
) ||
696 (nOldSttNdIdx
== mxInsertPosition
->GetNodeIdx() &&
697 pOld
->nSttCnt
== mxInsertPosition
->GetCntIdx() )))
698 break; // no attributes or Area
700 // set only the attributes that are different from the parent
701 if( pCurrent
&& pOld
->aAttrSet
.Count() )
703 SfxItemIter
aIter( pOld
->aAttrSet
);
704 const SfxPoolItem
* pItem
= aIter
.GetCurItem(), *pGet
;
707 if( SfxItemState::SET
== pCurrent
->aAttrSet
.GetItemState(
708 pItem
->Which(), false, &pGet
) &&
712 pItem
= aIter
.NextItem();
715 if (!pOld
->aAttrSet
.Count() && pOld
->maChildList
.empty() &&
720 // Set all attributes which have been defined from start until here
721 bool bCrsrBack
= !mxInsertPosition
->GetCntIdx();
724 // at the beginning of a paragraph? Move back one position
725 sal_Int32 nNd
= mxInsertPosition
->GetNodeIdx();
727 // if can not move backward then later don't move forward !
728 bCrsrBack
= nNd
!= mxInsertPosition
->GetNodeIdx();
731 if( pOld
->mxStartNodeIdx
->GetIdx() < mxInsertPosition
->GetNodeIdx() ||
732 ( pOld
->mxStartNodeIdx
->GetIdx() == mxInsertPosition
->GetNodeIdx() &&
733 pOld
->nSttCnt
<= mxInsertPosition
->GetCntIdx() ) )
737 // all pard attributes are only valid until the previous
739 if( nOldSttNdIdx
== mxInsertPosition
->GetNodeIdx() )
744 // Now it gets complicated:
745 // - all character attributes sre keep the area
746 // - all paragraph attributes to get the area
747 // up to the previous paragraph
748 auto xNew
= std::make_unique
<SvxRTFItemStackType
>(*pOld
, *mxInsertPosition
, true);
749 xNew
->aAttrSet
.SetParent( pOld
->aAttrSet
.GetParent() );
751 // Delete all paragraph attributes from xNew
752 for (const auto& pair
: aPardMap
.data
)
753 if (sal_uInt16 wid
= pair
.second
)
754 xNew
->aAttrSet
.ClearItem(wid
);
755 xNew
->SetRTFDefaults( GetRTFDefaults() );
758 if( xNew
->aAttrSet
.Count() == pOld
->aAttrSet
.Count() )
766 // Now span the real area of xNew from old
767 SetEndPrevPara( pOld
->mxEndNodeIdx
, pOld
->nEndCnt
);
770 if( IsChkStyleAttr() )
772 ClearStyleAttr_( *pOld
);
773 ClearStyleAttr_( *xNew
); //#i10381#, methinks.
778 pCurrent
->Add(std::move(pOld
));
779 pCurrent
->Add(std::move(xNew
));
783 // Last off the stack, thus cache it until the next text was
784 // read. (Span no attributes!)
786 m_AttrSetList
.push_back(std::move(pOld
));
787 m_AttrSetList
.push_back(std::move(xNew
));
794 pOld
->mxEndNodeIdx
= mxInsertPosition
->MakeNodeIdx();
795 pOld
->nEndCnt
= mxInsertPosition
->GetCntIdx();
799 If the parent (pCurrent) sets something e.g. , and the child (pOld)
800 unsets it and the style both are based on has it unset then
801 clearing the pOld by looking at the style is clearly a disaster
802 as the text ends up with pCurrents bold and not pOlds no bold, this
803 should be rethought out. For the moment its safest to just do
804 the clean if we have no parent, all we suffer is too many
805 redundant properties.
807 if (IsChkStyleAttr() && !pCurrent
)
808 ClearStyleAttr_( *pOld
);
812 pCurrent
->Add(std::move(pOld
));
813 // split up and create new entry, because it makes no sense
814 // to create a "so long" depend list. Bug 95010
815 if (bCrsrBack
&& 50 < pCurrent
->maChildList
.size())
817 // at the beginning of a paragraph? Move back one position
822 auto xNew(std::make_unique
<SvxRTFItemStackType
>(*pCurrent
, *mxInsertPosition
, true));
823 xNew
->SetRTFDefaults( GetRTFDefaults() );
825 // Set all until here valid Attributes
827 pCurrent
= aAttrStack
.empty() ? nullptr : aAttrStack
.back().get(); // can be changed after AttrGroupEnd!
828 xNew
->aAttrSet
.SetParent( pCurrent
? &pCurrent
->aAttrSet
: nullptr );
829 aAttrStack
.push_back( std::move(xNew
) );
833 // Last off the stack, thus cache it until the next text was
834 // read. (Span no attributes!)
835 m_AttrSetList
.push_back(std::move(pOld
));
839 // at the beginning of a paragraph? Move back one position
847 void SvxRTFParser::SetAllAttrOfStk() // end all Attr. and set it into doc
849 // repeat until all attributes will be taken from stack
850 while( !aAttrStack
.empty() )
853 for (size_t n
= m_AttrSetList
.size(); n
; )
855 auto const& pStkSet
= m_AttrSetList
[--n
];
856 SetAttrSet( *pStkSet
);
857 pStkSet
->DropChildList();
858 m_AttrSetList
.pop_back();
862 // sets all the attributes that are different from the current
863 void SvxRTFParser::SetAttrSet( SvxRTFItemStackType
&rSet
)
865 // Was DefTab never read? then set to default
867 SetDefault( RTF_DEFTAB
, 720 );
869 if (!rSet
.maChildList
.empty())
870 rSet
.Compress( *this );
871 if( rSet
.aAttrSet
.Count() || rSet
.nStyleNo
)
872 SetAttrInDoc( rSet
);
874 // then process all the children
875 for (size_t n
= 0; n
< rSet
.maChildList
.size(); ++n
)
876 SetAttrSet( *(rSet
.maChildList
[ n
]) );
879 // Has no text been inserted yet? (SttPos from the top Stack entry!)
880 bool SvxRTFParser::IsAttrSttPos()
882 SvxRTFItemStackType
* pCurrent
= aAttrStack
.empty() ? nullptr : aAttrStack
.back().get();
883 return !pCurrent
|| (pCurrent
->mxStartNodeIdx
->GetIdx() == mxInsertPosition
->GetNodeIdx() &&
884 pCurrent
->nSttCnt
== mxInsertPosition
->GetCntIdx());
888 void SvxRTFParser::SetAttrInDoc( SvxRTFItemStackType
& )
892 void SvxRTFParser::BuildWhichTable()
896 // Here are the IDs for all paragraph attributes, which can be detected by
897 // SvxParser and can be set in a SfxItemSet. The IDs are set correctly through
898 // the SlotIds from POOL.
899 static constexpr sal_uInt16 WIDS1
[] {
900 SID_ATTR_PARA_LINESPACE
,
901 SID_ATTR_PARA_ADJUST
,
903 SID_ATTR_PARA_HYPHENZONE
,
907 SID_ATTR_BORDER_OUTER
,
908 SID_ATTR_BORDER_SHADOW
,
909 SID_ATTR_PARA_OUTLLEVEL
,
913 SID_ATTR_PARA_SCRIPTSPACE
,
914 SID_ATTR_PARA_HANGPUNCTUATION
,
915 SID_ATTR_PARA_FORBIDDEN_RULES
,
916 SID_ATTR_FRAMEDIRECTION
,
918 for (sal_uInt16 nWid
: WIDS1
)
920 sal_uInt16 nTrueWid
= pAttrPool
->GetTrueWhich(nWid
, false);
921 aPardMap
.data
[nWid
] = nTrueWid
;
924 aWhichMap
= aWhichMap
.MergeRange(nTrueWid
, nTrueWid
);
927 // Here are the IDs for all character attributes, which can be detected by
928 // SvxParser and can be set in a SfxItemSet. The IDs are set correctly through
929 // the SlotIds from POOL.
930 static constexpr sal_uInt16 WIDS
[] {
931 SID_ATTR_CHAR_CASEMAP
, SID_ATTR_BRUSH_CHAR
, SID_ATTR_CHAR_COLOR
,
932 SID_ATTR_CHAR_CONTOUR
, SID_ATTR_CHAR_STRIKEOUT
, SID_ATTR_CHAR_ESCAPEMENT
,
933 SID_ATTR_CHAR_FONT
, SID_ATTR_CHAR_FONTHEIGHT
, SID_ATTR_CHAR_KERNING
,
934 SID_ATTR_CHAR_LANGUAGE
, SID_ATTR_CHAR_POSTURE
, SID_ATTR_CHAR_SHADOWED
,
935 SID_ATTR_CHAR_UNDERLINE
, SID_ATTR_CHAR_OVERLINE
, SID_ATTR_CHAR_WEIGHT
,
936 SID_ATTR_CHAR_WORDLINEMODE
, SID_ATTR_CHAR_AUTOKERN
, SID_ATTR_CHAR_CJK_FONT
,
937 SID_ATTR_CHAR_CJK_FONTHEIGHT
, sal_uInt16(SID_ATTR_CHAR_CJK_LANGUAGE
), SID_ATTR_CHAR_CJK_POSTURE
,
938 SID_ATTR_CHAR_CJK_WEIGHT
, SID_ATTR_CHAR_CTL_FONT
, SID_ATTR_CHAR_CTL_FONTHEIGHT
,
939 SID_ATTR_CHAR_CTL_LANGUAGE
, SID_ATTR_CHAR_CTL_POSTURE
, SID_ATTR_CHAR_CTL_WEIGHT
,
940 SID_ATTR_CHAR_EMPHASISMARK
, SID_ATTR_CHAR_TWO_LINES
, SID_ATTR_CHAR_SCALEWIDTH
,
941 SID_ATTR_CHAR_ROTATED
, SID_ATTR_CHAR_RELIEF
, SID_ATTR_CHAR_HIDDEN
,
943 for (sal_uInt16 nWid
: WIDS
)
945 sal_uInt16 nTrueWid
= pAttrPool
->GetTrueWhich(nWid
, false);
946 aPlainMap
.data
[nWid
] = nTrueWid
;
949 aWhichMap
= aWhichMap
.MergeRange(nTrueWid
, nTrueWid
);
953 const SfxItemSet
& SvxRTFParser::GetRTFDefaults()
957 pRTFDefaults
.reset(new SfxItemSet(*pAttrPool
, aWhichMap
));
958 if (const sal_uInt16 nId
= aPardMap
[SID_ATTR_PARA_SCRIPTSPACE
])
960 SvxScriptSpaceItem
aItem( false, nId
);
962 pAttrPool
->SetPoolDefaultItem( aItem
);
964 pRTFDefaults
->Put( aItem
);
967 return *pRTFDefaults
;
971 SvxRTFStyleType::SvxRTFStyleType(SfxItemPool
& rPool
, const WhichRangesContainer
& pWhichRange
)
972 : aAttrSet(rPool
, pWhichRange
)
974 , nOutlineNo(sal_uInt8(-1)) // not set
978 SvxRTFItemStackType::SvxRTFItemStackType(
979 SfxItemPool
& rPool
, const WhichRangesContainer
& pWhichRange
,
980 const EditPosition
& rPos
)
981 : aAttrSet( rPool
, pWhichRange
)
982 , mxStartNodeIdx(rPos
.MakeNodeIdx())
983 #if !defined(__COVERITY__)
984 // coverity 2020 has difficulty wrt std::optional leading to bogus 'Uninitialized scalar variable'
985 , mxEndNodeIdx(mxStartNodeIdx
)
987 , nSttCnt(rPos
.GetCntIdx())
993 SvxRTFItemStackType::SvxRTFItemStackType(
994 const SvxRTFItemStackType
& rCpy
,
995 const EditPosition
& rPos
,
996 bool const bCopyAttr
)
997 : aAttrSet( *rCpy
.aAttrSet
.GetPool(), rCpy
.aAttrSet
.GetRanges() )
998 , mxStartNodeIdx(rPos
.MakeNodeIdx())
999 #if !defined(__COVERITY__)
1000 // coverity 2020 has difficulty wrt std::optional leading to bogus 'Uninitialized scalar variable'
1001 , mxEndNodeIdx(mxStartNodeIdx
)
1003 , nSttCnt(rPos
.GetCntIdx())
1005 , nStyleNo(rCpy
.nStyleNo
)
1007 aAttrSet
.SetParent( &rCpy
.aAttrSet
);
1009 aAttrSet
.Put( rCpy
.aAttrSet
);
1012 /* ofz#13491 SvxRTFItemStackType dtor recursively
1013 calls the dtor of its m_pChildList. The recurse
1014 depth can grow sufficiently to trigger asan.
1016 So breadth-first iterate through the nodes
1017 and make a flat vector of them which can
1018 be iterated through in order of most
1019 distant from root first and release
1020 their children linearly
1022 void SvxRTFItemStackType::DropChildList()
1024 if (maChildList
.empty())
1027 std::vector
<SvxRTFItemStackType
*> bfs
;
1028 std::queue
<SvxRTFItemStackType
*> aQueue
;
1031 while (!aQueue
.empty())
1033 auto* front
= aQueue
.front();
1035 if (!front
->maChildList
.empty())
1037 for (const auto& a
: front
->maChildList
)
1038 aQueue
.push(a
.get());
1039 bfs
.push_back(front
);
1043 for (auto it
= bfs
.rbegin(); it
!= bfs
.rend(); ++it
)
1045 SvxRTFItemStackType
* pNode
= *it
;
1046 pNode
->maChildList
.clear();
1050 SvxRTFItemStackType::~SvxRTFItemStackType()
1054 void SvxRTFItemStackType::Add(std::unique_ptr
<SvxRTFItemStackType
> pIns
)
1056 maChildList
.push_back(std::move(pIns
));
1059 void SvxRTFItemStackType::SetStartPos( const EditPosition
& rPos
)
1061 mxStartNodeIdx
= rPos
.MakeNodeIdx();
1062 mxEndNodeIdx
= mxStartNodeIdx
;
1063 nSttCnt
= rPos
.GetCntIdx();
1066 void SvxRTFItemStackType::Compress( const SvxRTFParser
& rParser
)
1068 ENSURE_OR_RETURN_VOID(!maChildList
.empty(), "Compress: ChildList empty");
1070 SvxRTFItemStackType
* pTmp
= maChildList
[0].get();
1072 if( !pTmp
->aAttrSet
.Count() ||
1073 mxStartNodeIdx
->GetIdx() != pTmp
->mxStartNodeIdx
->GetIdx() ||
1074 nSttCnt
!= pTmp
->nSttCnt
)
1077 EditNodeIdx aLastNd
= *pTmp
->mxEndNodeIdx
;
1078 sal_Int32 nLastCnt
= pTmp
->nEndCnt
;
1080 SfxItemSet
aMrgSet( pTmp
->aAttrSet
);
1081 for (size_t n
= 1; n
< maChildList
.size(); ++n
)
1083 pTmp
= maChildList
[n
].get();
1084 if (!pTmp
->maChildList
.empty())
1085 pTmp
->Compress( rParser
);
1088 ? (aLastNd
.GetIdx()+1 != pTmp
->mxStartNodeIdx
->GetIdx() ||
1089 !rParser
.IsEndPara( &aLastNd
, nLastCnt
) )
1090 : ( pTmp
->nSttCnt
!= nLastCnt
||
1091 aLastNd
.GetIdx() != pTmp
->mxStartNodeIdx
->GetIdx() ))
1093 while (++n
< maChildList
.size())
1095 pTmp
= maChildList
[n
].get();
1096 if (!pTmp
->maChildList
.empty())
1097 pTmp
->Compress( rParser
);
1104 // Search for all which are set over the whole area
1105 SfxItemIter
aIter( aMrgSet
);
1106 const SfxPoolItem
* pItem
;
1107 const SfxPoolItem
* pIterItem
= aIter
.GetCurItem();
1109 sal_uInt16 nWhich
= pIterItem
->Which();
1110 if( SfxItemState::SET
!= pTmp
->aAttrSet
.GetItemState( nWhich
,
1111 false, &pItem
) || *pItem
!= *pIterItem
)
1114 pIterItem
= aIter
.NextItem();
1117 if( !aMrgSet
.Count() )
1121 aLastNd
= *pTmp
->mxEndNodeIdx
;
1122 nLastCnt
= pTmp
->nEndCnt
;
1125 if( mxEndNodeIdx
->GetIdx() != aLastNd
.GetIdx() || nEndCnt
!= nLastCnt
)
1129 aAttrSet
.Put( aMrgSet
);
1131 size_t n
= 0, nChildLen
= maChildList
.size();
1132 while (n
< nChildLen
)
1134 pTmp
= maChildList
[n
].get();
1135 pTmp
->aAttrSet
.Differentiate( aMrgSet
);
1137 if (pTmp
->maChildList
.empty() && !pTmp
->aAttrSet
.Count() && !pTmp
->nStyleNo
)
1139 maChildList
.erase( maChildList
.begin() + n
);
1146 void SvxRTFItemStackType::SetRTFDefaults( const SfxItemSet
& rDefaults
)
1148 if( rDefaults
.Count() )
1150 SfxItemIter
aIter( rDefaults
);
1151 const SfxPoolItem
* pItem
= aIter
.GetCurItem();
1153 sal_uInt16 nWhich
= pItem
->Which();
1154 if( SfxItemState::SET
!= aAttrSet
.GetItemState( nWhich
, false ))
1155 aAttrSet
.Put(*pItem
);
1157 pItem
= aIter
.NextItem();
1162 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */