void SvxRTFParser::Continue( int nToken )
{
SvRTFParser::Continue( nToken );
SvParserState eStatus = GetStatus(); if (eStatus != SvParserState::Pending && eStatus != SvParserState::Error)
{
SetAllAttrOfStk(); //Regardless of what "color 0" is, word defaults to auto as the default colour. //e.g. see #i7713#
}
}
// is called for each token that is recognized in CallParser void SvxRTFParser::NextToken( int nToken )
{
sal_Unicode cCh; switch( nToken )
{ case RTF_COLORTBL: ReadColorTable(); break; case RTF_FONTTBL: ReadFontTable(); break; case RTF_STYLESHEET: ReadStyleTable(); break;
case RTF_DEFF: if( bNewDoc )
{ if (!m_FontTable.empty()) // Can immediately be set
SetDefault( nToken, nTokenValue ); else // is set after reading the font table
nDfltFont = int(nTokenValue);
} break;
case RTF_DEFTAB: case RTF_DEFLANG: if( bNewDoc )
SetDefault( nToken, nTokenValue ); break;
case RTF_PICT: ReadBitmapData(); break;
case RTF_LINE: cCh = '\n'; goto INSINGLECHAR; case RTF_TAB: cCh = '\t'; goto INSINGLECHAR; case RTF_SUBENTRYINDEX: cCh = ':'; goto INSINGLECHAR;
case RTF_EMDASH: cCh = 0x2014; goto INSINGLECHAR; case RTF_ENDASH: cCh = 0x2013; goto INSINGLECHAR; case RTF_BULLET: cCh = 0x2022; goto INSINGLECHAR; case RTF_LQUOTE: cCh = 0x2018; goto INSINGLECHAR; case RTF_RQUOTE: cCh = 0x2019; goto INSINGLECHAR; case RTF_LDBLQUOTE: cCh = 0x201C; goto INSINGLECHAR; case RTF_RDBLQUOTE: cCh = 0x201D; goto INSINGLECHAR;
INSINGLECHAR:
aToken = OUStringChar(cCh);
[[fallthrough]]; // aToken is set as Text case RTF_TEXTTOKEN:
{
InsertText(); // all collected Attributes are set for (size_t n = m_AttrSetList.size(); n; )
{ autoconst& pStkSet = m_AttrSetList[--n];
SetAttrSet( *pStkSet );
m_AttrSetList.pop_back();
}
} break;
case RTF_PAR:
InsertPara(); break; case'{': if (bNewGroup) // Nesting!
GetAttrSet_();
bNewGroup = true; break; case'}': if( !bNewGroup ) // Empty Group ??
AttrGroupEnd();
bNewGroup = false; break; case RTF_INFO:
SkipGroup(); break;
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // First overwrite all (all have to be in one group!!) // Could also appear in the RTF-file without the IGNORE-Flag; all Groups // with the IGNORE-Flag are overwritten in the default branch.
case RTF_SWG_PRTDATA: case RTF_FIELD: case RTF_ATNID: case RTF_ANNOTATION:
case RTF_BKMKSTART: case RTF_BKMKEND: case RTF_BKMK_KEY: case RTF_XE: case RTF_TC: case RTF_NEXTFILE: case RTF_TEMPLATE: // RTF_SHPRSLT disabled for #i19718#
SkipGroup(); break; // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
case RTF_PGDSCNO: case RTF_PGBRK: case RTF_SHADOW: if( RTF_IGNOREFLAG != GetStackPtr( -1 )->nTokenId ) break;
nToken = SkipToken(); if( '{' == GetStackPtr( -1 )->nTokenId )
nToken = SkipToken();
ReadAttr( nToken, &GetAttrSet() ); break;
default: switch( nToken & ~(0xff | RTF_SWGDEFS) )
{ case RTF_PARFMT: // here are no SWGDEFS
ReadAttr( nToken, &GetAttrSet() ); break;
case RTF_CHRFMT: case RTF_BRDRDEF: case RTF_TABSTOPDEF:
void SvxRTFParser::ReadStyleTable()
{ int bSaveChkStyleAttr = bChkStyleAttr ? 1 : 0;
sal_uInt16 nStyleNo = 0; bool bHasStyleNo = false; int _nOpenBrackets = 1; // the first was already detected earlier!!
std::optional<SvxRTFStyleType> xStyle(SvxRTFStyleType(*pAttrPool, aWhichMap));
xStyle->aAttrSet.Put( GetRTFDefaults() );
bIsInReadStyleTab = true;
bChkStyleAttr = false; // Do not check Attribute against the Styles
while( _nOpenBrackets && IsParserWorking() )
{ int nToken = GetNextToken(); switch( nToken )
{ case'}': if( --_nOpenBrackets && IsParserWorking() ) // Style has been completely read, // so this is still a stable status
SaveState( RTF_STYLESHEET ); break; case'{':
{ if( RTF_IGNOREFLAG != GetNextToken() )
SkipToken(); elseif( RTF_UNKNOWNCONTROL != ( nToken = GetNextToken() ) &&
RTF_PN != nToken )
SkipToken( -2 ); else
{ // filter out at once
ReadUnknownData();
nToken = GetNextToken(); if( '}' != nToken )
eState = SvParserState::Error; break;
}
++_nOpenBrackets;
} break;
case RTF_SBASEDON: xStyle->nBasedOn = sal_uInt16(nTokenValue); break; case RTF_SNEXT: break; case RTF_OUTLINELEVEL: case RTF_SOUTLVL: xStyle->nOutlineNo = sal_uInt8(nTokenValue); break; case RTF_S: nStyleNo = static_cast<short>(nTokenValue);
bHasStyleNo = true; break; case RTF_CS: nStyleNo = static_cast<short>(nTokenValue);
bHasStyleNo = true; break;
case RTF_TEXTTOKEN: if (bHasStyleNo)
{
DelCharAtEnd( aToken, ';' );
xStyle->sName = aToken.toString();
if (!m_StyleTable.empty())
{
m_StyleTable.erase(nStyleNo);
} // All data from the font is available, so off to the table
m_StyleTable.emplace(nStyleNo, std::move(*xStyle));
xStyle.emplace(*pAttrPool, aWhichMap);
xStyle->aAttrSet.Put( GetRTFDefaults() );
nStyleNo = 0;
bHasStyleNo = false;
} break; default: switch( nToken & ~(0xff | RTF_SWGDEFS) )
{ case RTF_PARFMT: // here are no SWGDEFS
ReadAttr( nToken, &xStyle->aAttrSet ); break;
case RTF_CHRFMT: case RTF_BRDRDEF: case RTF_TABSTOPDEF: #ifndef NDEBUG auto nEnteringToken = nToken; #endif auto nEnteringIndex = m_nTokenIndex; int nSkippedTokens = 0; if( RTF_SWGDEFS & nToken)
{ if( RTF_IGNOREFLAG != GetStackPtr( -1 )->nTokenId ) break;
nToken = SkipToken();
++nSkippedTokens; if( '{' == GetStackPtr( -1 )->nTokenId )
{
nToken = SkipToken();
++nSkippedTokens;
}
}
ReadAttr( nToken, &xStyle->aAttrSet ); if (nSkippedTokens && m_nTokenIndex == nEnteringIndex - nSkippedTokens)
{ // we called SkipToken to go back one or two, but ReadAttrs // read nothing, so on next loop of the outer while we // would end up in the same state again (assert that)
assert(nEnteringToken == GetNextToken()); // and loop endlessly, skip format a token // instead to avoid that
SkipToken(nSkippedTokens);
} break;
} break;
}
}
xStyle.reset(); // Delete the Last Style
SkipToken(); // the closing brace is evaluated "above"
// Flag back to old state
bChkStyleAttr = bSaveChkStyleAttr;
bIsInReadStyleTab = false;
}
for (;;)
{
nToken = GetNextToken(); if ( '}' == nToken || !IsParserWorking() ) break; switch( nToken )
{ case RTF_RED: nRed = sal_uInt8(nTokenValue); break; case RTF_GREEN: nGreen = sal_uInt8(nTokenValue); break; case RTF_BLUE: nBlue = sal_uInt8(nTokenValue); break;
case RTF_TEXTTOKEN: if( 1 == aToken.getLength()
? aToken[ 0 ] != ';'
: -1 == aToken.indexOf( ";" ) ) break; // At least the ';' must be found
[[fallthrough]];
case';': if( IsParserWorking() )
{ // one color is finished, fill in the table // try to map the values to SV internal names
Color aColor( nRed, nGreen, nBlue ); if( maColorTable.empty() &&
sal_uInt8(-1) == nRed && sal_uInt8(-1) == nGreen && sal_uInt8(-1) == nBlue )
aColor = COL_AUTO;
maColorTable.push_back( aColor );
nRed = 0;
nGreen = 0;
nBlue = 0;
// Color has been completely read, // so this is still a stable status
SaveState( RTF_COLORTBL );
} break;
}
}
SkipToken(); // the closing brace is evaluated "above"
}
void SvxRTFParser::ReadFontTable()
{ int _nOpenBrackets = 1; // the first was already detected earlier!!
vcl::Font aFont; short nFontNo(0), nInsFontNo (0);
OUString sAltNm, sFntNm; bool bIsAltFntNm = false;
while( _nOpenBrackets && IsParserWorking() )
{ bool bCheckNewFont = false; int nToken = GetNextToken(); switch( nToken )
{ case'}':
bIsAltFntNm = false; // Style has been completely read, // so this is still a stable status if( --_nOpenBrackets <= 1 && IsParserWorking() )
SaveState( RTF_FONTTBL );
bCheckNewFont = true;
nInsFontNo = nFontNo; break; case'{': if( RTF_IGNOREFLAG != GetNextToken() )
SkipToken(); // immediately skip unknown and all known but non-evaluated // groups elseif( RTF_UNKNOWNCONTROL != ( nToken = GetNextToken() ) &&
RTF_PANOSE != nToken && RTF_FNAME != nToken &&
RTF_FONTEMB != nToken && RTF_FONTFILE != nToken )
SkipToken( -2 ); else
{ // filter out at once
ReadUnknownData();
nToken = GetNextToken(); if( '}' != nToken )
eState = SvParserState::Error; break;
}
++_nOpenBrackets; break; case RTF_FROMAN:
aFont.SetFamily( FAMILY_ROMAN ); break; case RTF_FSWISS:
aFont.SetFamily( FAMILY_SWISS ); break; case RTF_FMODERN:
aFont.SetFamily( FAMILY_MODERN ); break; case RTF_FSCRIPT:
aFont.SetFamily( FAMILY_SCRIPT ); break; case RTF_FDECOR:
aFont.SetFamily( FAMILY_DECORATIVE ); break; // for technical/symbolic font of the rtl_TextEncoding is changed! case RTF_FTECH:
aFont.SetCharSet( RTL_TEXTENCODING_SYMBOL );
[[fallthrough]]; case RTF_FNIL:
aFont.SetFamily( FAMILY_DONTKNOW ); break; case RTF_FCHARSET: if (-1 != nTokenValue)
{
rtl_TextEncoding nrtl_TextEncoding = rtl_getTextEncodingFromWindowsCharset( static_cast<sal_uInt8>(nTokenValue));
aFont.SetCharSet(nrtl_TextEncoding); //When we're in a font, the fontname is in the font //charset, except for symbol fonts I believe if (nrtl_TextEncoding == RTL_TEXTENCODING_SYMBOL)
nrtl_TextEncoding = RTL_TEXTENCODING_DONTKNOW;
SetEncoding(nrtl_TextEncoding);
} break; case RTF_FPRQ: switch( nTokenValue )
{ case1:
aFont.SetPitch( PITCH_FIXED ); break; case2:
aFont.SetPitch( PITCH_VARIABLE ); break;
} break; case RTF_F:
bCheckNewFont = true;
nInsFontNo = nFontNo;
nFontNo = static_cast<short>(nTokenValue); break; case RTF_FALT:
bIsAltFntNm = true; break; case RTF_TEXTTOKEN:
DelCharAtEnd( aToken, ';' ); if ( !aToken.isEmpty() )
{ if( bIsAltFntNm )
sAltNm = aToken; else
sFntNm = aToken;
} break;
}
if( bCheckNewFont && 1 >= _nOpenBrackets && !sFntNm.isEmpty() ) // one font is ready
{ // All data from the font is available, so off to the table if (!sAltNm.isEmpty())
sFntNm += ";" + sAltNm;
void SvxRTFParser::ClearStyleAttr_( SvxRTFItemStackType& rStkType )
{ // check attributes to the attributes of the stylesheet or to // the default attrs of the document
SfxItemSet &rSet = rStkType.GetAttrSet(); const SfxItemPool& rPool = *rSet.GetPool(); const SfxPoolItem* pItem;
SfxWhichIter aIter( rSet );
do { // middle check loop
sal_Int32 nOldSttNdIdx = pOld->mxStartNodeIdx->GetIdx(); if (pOld->maChildList.empty() &&
((!pOld->aAttrSet.Count() && !pOld->nStyleNo ) ||
(nOldSttNdIdx == mxInsertPosition->GetNodeIdx() &&
pOld->nSttCnt == mxInsertPosition->GetCntIdx() ))) break; // no attributes or Area
// set only the attributes that are different from the parent if( pCurrent && pOld->aAttrSet.Count() )
{ // ITEM: SfxItemIter and removing SfxPoolItems: // iterating and clearing Items on the same incarnation is in // general a bad idea, it invalidates iterators. Work around // this by remembering the WhichIDs of Items to delete
std::vector<sal_uInt16> aDeleteWhichIDs;
for (auto nDelWhich : aDeleteWhichIDs)
pOld->aAttrSet.ClearItem(nDelWhich);
if (!pOld->aAttrSet.Count() && pOld->maChildList.empty() &&
!pOld->nStyleNo ) break;
}
// Set all attributes which have been defined from start until here bool bCrsrBack = !mxInsertPosition->GetCntIdx(); if( bCrsrBack )
{ // at the beginning of a paragraph? Move back one position
sal_Int32 nNd = mxInsertPosition->GetNodeIdx();
MovePos(false); // if can not move backward then later don't move forward !
bCrsrBack = nNd != mxInsertPosition->GetNodeIdx();
}
if( pOld->mxStartNodeIdx->GetIdx() < mxInsertPosition->GetNodeIdx() ||
( pOld->mxStartNodeIdx->GetIdx() == mxInsertPosition->GetNodeIdx() &&
pOld->nSttCnt <= mxInsertPosition->GetCntIdx() ) )
{ if( !bCrsrBack )
{ // all pard attributes are only valid until the previous // paragraph !! if( nOldSttNdIdx == mxInsertPosition->GetNodeIdx() )
{
} else
{ // Now it gets complicated: // - all character attributes sre keep the area // - all paragraph attributes to get the area // up to the previous paragraph auto xNew = std::make_unique<SvxRTFItemStackType>(*pOld, *mxInsertPosition, true);
xNew->aAttrSet.SetParent( pOld->aAttrSet.GetParent() );
// Delete all paragraph attributes from xNew for (constauto& pair : aPardMap.data) if (sal_uInt16 wid = pair.second)
xNew->aAttrSet.ClearItem(wid);
xNew->SetRTFDefaults( GetRTFDefaults() );
// Were there any? if( xNew->aAttrSet.Count() == pOld->aAttrSet.Count() )
{
xNew.reset();
} else
{
xNew->nStyleNo = 0;
// Now span the real area of xNew from old
SetEndPrevPara( pOld->mxEndNodeIdx, pOld->nEndCnt );
xNew->nSttCnt = 0;
if( pCurrent )
{
pCurrent->Add(std::move(pOld));
pCurrent->Add(std::move(xNew));
} else
{ // Last off the stack, thus cache it until the next text was // read. (Span no attributes!)
if( pCurrent )
{
pCurrent->Add(std::move(pOld)); // split up and create new entry, because it makes no sense // to create a "so long" depend list. Bug 95010 if (bCrsrBack && 50 < pCurrent->maChildList.size())
{ // at the beginning of a paragraph? Move back one position
MovePos();
bCrsrBack = false;
// Open a new Group. auto xNew(std::make_unique<SvxRTFItemStackType>(*pCurrent, *mxInsertPosition, true));
xNew->SetRTFDefaults( GetRTFDefaults() );
// Set all until here valid Attributes
AttrGroupEnd();
pCurrent = aAttrStack.empty() ? nullptr : aAttrStack.back().get(); // can be changed after AttrGroupEnd!
xNew->aAttrSet.SetParent( pCurrent ? &pCurrent->aAttrSet : nullptr );
aAttrStack.push_back( std::move(xNew) );
}
} else // Last off the stack, thus cache it until the next text was // read. (Span no attributes!)
m_AttrSetList.push_back(std::move(pOld));
}
if( bCrsrBack ) // at the beginning of a paragraph? Move back one position
MovePos();
} while( false );
bNewGroup = false;
}
void SvxRTFParser::SetAllAttrOfStk() // end all Attr. and set it into doc
{ // repeat until all attributes will be taken from stack while( !aAttrStack.empty() )
AttrGroupEnd();
for (size_t n = m_AttrSetList.size(); n; )
{ autoconst& pStkSet = m_AttrSetList[--n];
SetAttrSet( *pStkSet );
pStkSet->DropChildList();
m_AttrSetList.pop_back();
}
}
// sets all the attributes that are different from the current void SvxRTFParser::SetAttrSet( SvxRTFItemStackType &rSet )
{ // Was DefTab never read? then set to default if( !bIsSetDfltTab )
SetDefault( RTF_DEFTAB, 720 );
// then process all the children for (size_t n = 0; n < rSet.maChildList.size(); ++n)
SetAttrSet( *(rSet.maChildList[ n ]) );
}
// Has no text been inserted yet? (SttPos from the top Stack entry!) bool SvxRTFParser::IsAttrSttPos()
{
SvxRTFItemStackType* pCurrent = aAttrStack.empty() ? nullptr : aAttrStack.back().get(); return !pCurrent || (pCurrent->mxStartNodeIdx->GetIdx() == mxInsertPosition->GetNodeIdx() &&
pCurrent->nSttCnt == mxInsertPosition->GetCntIdx());
}
// Here are the IDs for all paragraph attributes, which can be detected by // SvxParser and can be set in a SfxItemSet. The IDs are set correctly through // the SlotIds from POOL. static constexpr sal_uInt16 WIDS1[] {
SID_ATTR_PARA_LINESPACE,
SID_ATTR_PARA_ADJUST,
SID_ATTR_TABSTOP,
SID_ATTR_PARA_HYPHENZONE,
SID_ATTR_LRSPACE,
SID_ATTR_ULSPACE,
SID_ATTR_BRUSH,
SID_ATTR_BORDER_OUTER,
SID_ATTR_BORDER_SHADOW,
SID_ATTR_PARA_OUTLLEVEL,
SID_ATTR_PARA_SPLIT,
SID_ATTR_PARA_KEEP,
SID_PARA_VERTALIGN,
SID_ATTR_PARA_SCRIPTSPACE,
SID_ATTR_PARA_HANGPUNCTUATION,
SID_ATTR_PARA_FORBIDDEN_RULES,
SID_ATTR_FRAMEDIRECTION,
}; for (sal_uInt16 nWid : WIDS1)
{
sal_uInt16 nTrueWid = pAttrPool->GetTrueWhichIDFromSlotID(nWid, false);
aPardMap.data[nWid] = nTrueWid; if (nTrueWid == 0) continue;
aWhichMap = aWhichMap.MergeRange(nTrueWid, nTrueWid);
}
// Here are the IDs for all character attributes, which can be detected by // SvxParser and can be set in a SfxItemSet. The IDs are set correctly through // the SlotIds from POOL. static constexpr sal_uInt16 WIDS[] {
SID_ATTR_CHAR_CASEMAP, SID_ATTR_BRUSH_CHAR, SID_ATTR_CHAR_COLOR,
SID_ATTR_CHAR_CONTOUR, SID_ATTR_CHAR_STRIKEOUT, SID_ATTR_CHAR_ESCAPEMENT,
SID_ATTR_CHAR_FONT, SID_ATTR_CHAR_FONTHEIGHT, SID_ATTR_CHAR_KERNING,
SID_ATTR_CHAR_LANGUAGE, SID_ATTR_CHAR_POSTURE, SID_ATTR_CHAR_SHADOWED,
SID_ATTR_CHAR_UNDERLINE, SID_ATTR_CHAR_OVERLINE, SID_ATTR_CHAR_WEIGHT,
SID_ATTR_CHAR_WORDLINEMODE, SID_ATTR_CHAR_AUTOKERN, SID_ATTR_CHAR_CJK_FONT,
SID_ATTR_CHAR_CJK_FONTHEIGHT, sal_uInt16(SID_ATTR_CHAR_CJK_LANGUAGE), SID_ATTR_CHAR_CJK_POSTURE,
SID_ATTR_CHAR_CJK_WEIGHT, SID_ATTR_CHAR_CTL_FONT, SID_ATTR_CHAR_CTL_FONTHEIGHT,
SID_ATTR_CHAR_CTL_LANGUAGE, SID_ATTR_CHAR_CTL_POSTURE, SID_ATTR_CHAR_CTL_WEIGHT,
SID_ATTR_CHAR_EMPHASISMARK, SID_ATTR_CHAR_TWO_LINES, SID_ATTR_CHAR_SCALEWIDTH,
SID_ATTR_CHAR_ROTATED, SID_ATTR_CHAR_RELIEF, SID_ATTR_CHAR_HIDDEN,
}; for (sal_uInt16 nWid : WIDS)
{
sal_uInt16 nTrueWid = pAttrPool->GetTrueWhichIDFromSlotID(nWid, false);
aPlainMap.data[nWid] = nTrueWid; if (nTrueWid == 0) continue;
aWhichMap = aWhichMap.MergeRange(nTrueWid, nTrueWid);
}
}
while (!aQueue.empty())
{ auto* front = aQueue.front();
aQueue.pop(); if (!front->maChildList.empty())
{ for (constauto& a : front->maChildList)
aQueue.push(a.get());
bfs.push_back(front);
}
}
for (auto it = bfs.rbegin(); it != bfs.rend(); ++it)
{
SvxRTFItemStackType* pNode = *it;
pNode->maChildList.clear();
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.