Coverage Report

Created: 2026-03-31 11:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/editeng/source/rtf/svxrtf.cxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
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/.
8
 *
9
 * This file incorporates work covered by the following license notice:
10
 *
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 .
18
 */
19
20
#include <memory>
21
#include <queue>
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 <comphelper/configuration.hxx>
31
32
#include <editeng/scriptspaceitem.hxx>
33
#include <editeng/fontitem.hxx>
34
#include <editeng/svxrtf.hxx>
35
#include <editeng/editids.hrc>
36
#include <vcl/font.hxx>
37
#include <vcl/svapp.hxx>
38
#include <vcl/settings.hxx>
39
40
41
using namespace ::com::sun::star;
42
43
44
static rtl_TextEncoding lcl_GetDefaultTextEncodingForRTF()
45
1.03k
{
46
47
1.03k
    OUString aLangString( Application::GetSettings().GetLanguageTag().getLanguage());
48
49
1.03k
    if ( aLangString == "ru" || aLangString == "uk" )
50
0
        return RTL_TEXTENCODING_MS_1251;
51
1.03k
    if ( aLangString == "tr" )
52
0
        return RTL_TEXTENCODING_MS_1254;
53
1.03k
    else
54
1.03k
        return RTL_TEXTENCODING_MS_1252;
55
1.03k
}
56
57
// -------------- Methods --------------------
58
59
SvxRTFParser::SvxRTFParser( SfxItemPool& rPool, SvStream& rIn )
60
10.9k
    : SvRTFParser( rIn, 5 )
61
10.9k
    , pAttrPool( &rPool )
62
10.9k
    , nDfltFont( 0)
63
10.9k
    , bNewDoc( true )
64
10.9k
    , bNewGroup( false)
65
10.9k
    , bIsSetDfltTab( false)
66
10.9k
    , bChkStyleAttr( false )
67
10.9k
    , bCalcValue( false )
68
10.9k
    , bIsLeftToRightDef( true)
69
10.9k
    , bIsInReadStyleTab( false)
70
10.9k
{
71
10.9k
    pDfltFont.emplace();
72
10.9k
    mxDefaultColor = Color();
73
74
    // generate the correct WhichId table from the set WhichIds.
75
10.9k
    BuildWhichTable();
76
10.9k
}
77
78
SvxRTFParser::~SvxRTFParser()
79
10.9k
{
80
10.9k
    if( !aAttrStack.empty() )
81
6.20k
        ClearAttrStack();
82
10.9k
}
83
84
void SvxRTFParser::SetInsPos( const EditPosition& rNew )
85
10.9k
{
86
10.9k
    mxInsertPosition = rNew;
87
10.9k
}
88
89
SvParserState SvxRTFParser::CallParser()
90
10.9k
{
91
10.9k
    DBG_ASSERT( mxInsertPosition, "no insertion position");
92
93
10.9k
    if( !mxInsertPosition )
94
0
        return SvParserState::Error;
95
96
10.9k
    if( !maColorTable.empty() )
97
0
        ClearColorTbl();
98
10.9k
    m_FontTable.clear();
99
10.9k
    m_StyleTable.clear();
100
10.9k
    if( !aAttrStack.empty() )
101
0
        ClearAttrStack();
102
103
10.9k
    bIsSetDfltTab = false;
104
10.9k
    bNewGroup = false;
105
10.9k
    nDfltFont = 0;
106
107
10.9k
    return SvRTFParser::CallParser();
108
10.9k
}
109
110
void SvxRTFParser::Continue( int nToken )
111
10.7k
{
112
10.7k
    SvRTFParser::Continue( nToken );
113
114
10.7k
    SvParserState eStatus = GetStatus();
115
10.7k
    if (eStatus != SvParserState::Pending && eStatus != SvParserState::Error)
116
730
    {
117
730
        SetAllAttrOfStk();
118
    //Regardless of what "color 0" is, word defaults to auto as the default colour.
119
    //e.g. see #i7713#
120
730
    }
121
10.7k
}
122
123
124
// is called for each token that is recognized in CallParser
125
void SvxRTFParser::NextToken( int nToken )
126
1.81M
{
127
1.81M
    sal_Unicode cCh;
128
1.81M
    switch( nToken )
129
1.81M
    {
130
918
    case RTF_COLORTBL:      ReadColorTable();       break;
131
1.03k
    case RTF_FONTTBL:       ReadFontTable();        break;
132
599
    case RTF_STYLESHEET:    ReadStyleTable();       break;
133
134
0
    case RTF_DEFF:
135
0
            if( bNewDoc )
136
0
            {
137
0
                if (!m_FontTable.empty())
138
                    // Can immediately be set
139
0
                    SetDefault( nToken, nTokenValue );
140
0
                else
141
                    // is set after reading the font table
142
0
                    nDfltFont = int(nTokenValue);
143
0
            }
144
0
            break;
145
146
0
    case RTF_DEFTAB:
147
425
    case RTF_DEFLANG:
148
425
            if( bNewDoc )
149
0
                SetDefault( nToken, nTokenValue );
150
425
            break;
151
152
153
27
    case RTF_PICT:          ReadBitmapData();       break;
154
155
0
    case RTF_LINE:          cCh = '\n'; goto INSINGLECHAR;
156
3.98k
    case RTF_TAB:           cCh = '\t'; goto INSINGLECHAR;
157
2.47k
    case RTF_SUBENTRYINDEX: cCh = ':';  goto INSINGLECHAR;
158
159
76
    case RTF_EMDASH:        cCh = 0x2014;   goto INSINGLECHAR;
160
397
    case RTF_ENDASH:        cCh = 0x2013;   goto INSINGLECHAR;
161
105
    case RTF_BULLET:        cCh = 0x2022;   goto INSINGLECHAR;
162
91
    case RTF_LQUOTE:        cCh = 0x2018;   goto INSINGLECHAR;
163
196
    case RTF_RQUOTE:        cCh = 0x2019;   goto INSINGLECHAR;
164
113
    case RTF_LDBLQUOTE:     cCh = 0x201C;   goto INSINGLECHAR;
165
251
    case RTF_RDBLQUOTE:     cCh = 0x201D;   goto INSINGLECHAR;
166
7.68k
INSINGLECHAR:
167
7.68k
        aToken = OUStringChar(cCh);
168
7.68k
        [[fallthrough]]; // aToken is set as Text
169
1.10M
    case RTF_TEXTTOKEN:
170
1.10M
        {
171
1.10M
            InsertText();
172
            // all collected Attributes are set
173
1.15M
            for (size_t n = m_AttrSetList.size(); n; )
174
46.8k
            {
175
46.8k
                auto const& pStkSet = m_AttrSetList[--n];
176
46.8k
                SetAttrSet( *pStkSet );
177
46.8k
                m_AttrSetList.pop_back();
178
46.8k
            }
179
1.10M
        }
180
1.10M
        break;
181
182
183
315k
    case RTF_PAR:
184
315k
        InsertPara();
185
315k
        break;
186
109k
    case '{':
187
109k
        if (bNewGroup)          // Nesting!
188
57.9k
            GetAttrSet_();
189
109k
        bNewGroup = true;
190
109k
        break;
191
54.7k
    case '}':
192
54.7k
        if( !bNewGroup )        // Empty Group ??
193
37.7k
            AttrGroupEnd();
194
54.7k
        bNewGroup = false;
195
54.7k
        break;
196
200
    case RTF_INFO:
197
200
        SkipGroup();
198
200
        break;
199
200
    // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
201
    // First overwrite all (all have to be in one group!!)
202
    // Could also appear in the RTF-file without the IGNORE-Flag; all Groups
203
    // with the IGNORE-Flag are overwritten in the default branch.
204
205
1
    case RTF_SWG_PRTDATA:
206
1
    case RTF_FIELD:
207
22
    case RTF_ATNID:
208
40
    case RTF_ANNOTATION:
209
210
186
    case RTF_BKMKSTART:
211
322
    case RTF_BKMKEND:
212
322
    case RTF_BKMK_KEY:
213
363
    case RTF_XE:
214
375
    case RTF_TC:
215
375
    case RTF_NEXTFILE:
216
377
    case RTF_TEMPLATE:
217
    // RTF_SHPRSLT disabled for #i19718#
218
377
                            SkipGroup();
219
377
                            break;
220
    // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
221
222
332
    case RTF_PGDSCNO:
223
332
    case RTF_PGBRK:
224
817
    case RTF_SHADOW:
225
817
            if( RTF_IGNOREFLAG != GetStackPtr( -1 )->nTokenId )
226
166
                break;
227
651
            nToken = SkipToken();
228
651
            if( '{' == GetStackPtr( -1 )->nTokenId )
229
424
                nToken = SkipToken();
230
231
651
            ReadAttr( nToken, &GetAttrSet() );
232
651
            break;
233
234
227k
    default:
235
227k
        switch( nToken & ~(0xff | RTF_SWGDEFS) )
236
227k
        {
237
50.9k
        case RTF_PARFMT:        // here are no SWGDEFS
238
50.9k
            ReadAttr( nToken, &GetAttrSet() );
239
50.9k
            break;
240
241
79.8k
        case RTF_CHRFMT:
242
83.8k
        case RTF_BRDRDEF:
243
87.6k
        case RTF_TABSTOPDEF:
244
245
87.6k
            if( RTF_SWGDEFS & nToken)
246
479
            {
247
479
                if( RTF_IGNOREFLAG != GetStackPtr( -1 )->nTokenId )
248
185
                    break;
249
294
                nToken = SkipToken();
250
294
                if( '{' == GetStackPtr( -1 )->nTokenId )
251
286
                {
252
286
                    nToken = SkipToken();
253
286
                }
254
294
            }
255
87.4k
            ReadAttr( nToken, &GetAttrSet() );
256
87.4k
            break;
257
88.6k
        default:
258
88.6k
            {
259
88.6k
                if( RTF_IGNOREFLAG == GetStackPtr( -1 )->nTokenId &&
260
1.42k
                      '{' == GetStackPtr( -2 )->nTokenId )
261
1.10k
                    SkipGroup();
262
88.6k
            }
263
88.6k
            break;
264
227k
        }
265
227k
        break;
266
1.81M
    }
267
1.81M
}
268
269
void SvxRTFParser::ReadStyleTable()
270
599
{
271
599
    int bSaveChkStyleAttr = bChkStyleAttr ? 1 : 0;
272
599
    sal_uInt16 nStyleNo = 0;
273
599
    bool bHasStyleNo = false;
274
599
    int _nOpenBrackets = 1;      // the first was already detected earlier!!
275
599
    std::optional<SvxRTFStyleType> xStyle(SvxRTFStyleType(*pAttrPool, aWhichMap));
276
599
    xStyle->aAttrSet.Put( GetRTFDefaults() );
277
278
599
    bIsInReadStyleTab = true;
279
599
    bChkStyleAttr = false;      // Do not check Attribute against the Styles
280
281
125k
    while( _nOpenBrackets && IsParserWorking() )
282
124k
    {
283
124k
        int nToken = GetNextToken();
284
124k
        switch( nToken )
285
124k
        {
286
6.99k
        case '}':       if( --_nOpenBrackets && IsParserWorking() )
287
                            // Style has been completely read,
288
                            // so this is still a stable status
289
6.72k
                            SaveState( RTF_STYLESHEET );
290
6.99k
                        break;
291
14.3k
        case '{':
292
14.3k
            {
293
14.3k
                if( RTF_IGNOREFLAG != GetNextToken() )
294
11.7k
                    SkipToken();
295
2.57k
                else if( RTF_UNKNOWNCONTROL != ( nToken = GetNextToken() ) &&
296
2.47k
                            RTF_PN != nToken )
297
2.43k
                    SkipToken( -2 );
298
142
                else
299
142
                {
300
                    // filter out at once
301
142
                    ReadUnknownData();
302
142
                    nToken = GetNextToken();
303
142
                    if( '}' != nToken )
304
8
                        eState = SvParserState::Error;
305
142
                    break;
306
142
                }
307
14.2k
                ++_nOpenBrackets;
308
14.2k
            }
309
0
            break;
310
311
2.34k
        case RTF_SBASEDON:  xStyle->nBasedOn = sal_uInt16(nTokenValue); break;
312
2.98k
        case RTF_SNEXT:     break;
313
251
        case RTF_OUTLINELEVEL:
314
316
        case RTF_SOUTLVL:   xStyle->nOutlineNo = sal_uInt8(nTokenValue);    break;
315
14.3k
        case RTF_S:         nStyleNo = static_cast<short>(nTokenValue);
316
14.3k
                            bHasStyleNo = true;
317
14.3k
                            break;
318
1.20k
        case RTF_CS:        nStyleNo = static_cast<short>(nTokenValue);
319
1.20k
                            bHasStyleNo = true;
320
1.20k
                            break;
321
322
41.3k
        case RTF_TEXTTOKEN:
323
41.3k
            if (bHasStyleNo)
324
14.8k
            {
325
14.8k
                DelCharAtEnd( aToken, ';' );
326
14.8k
                xStyle->sName = aToken.toString();
327
328
14.8k
                if (!m_StyleTable.empty())
329
14.4k
                {
330
14.4k
                    m_StyleTable.erase(nStyleNo);
331
14.4k
                }
332
                // All data from the font is available, so off to the table
333
14.8k
                m_StyleTable.emplace(nStyleNo, std::move(*xStyle));
334
14.8k
                xStyle.emplace(*pAttrPool, aWhichMap);
335
14.8k
                xStyle->aAttrSet.Put( GetRTFDefaults() );
336
14.8k
                nStyleNo = 0;
337
14.8k
                bHasStyleNo = false;
338
14.8k
            }
339
41.3k
            break;
340
40.8k
        default:
341
40.8k
            switch( nToken & ~(0xff | RTF_SWGDEFS) )
342
40.8k
            {
343
6.97k
            case RTF_PARFMT:        // here are no SWGDEFS
344
6.97k
                ReadAttr( nToken, &xStyle->aAttrSet );
345
6.97k
                break;
346
347
9.26k
            case RTF_CHRFMT:
348
10.0k
            case RTF_BRDRDEF:
349
11.9k
            case RTF_TABSTOPDEF:
350
#ifndef NDEBUG
351
                auto nEnteringToken = nToken;
352
#endif
353
11.9k
                auto nEnteringIndex = m_nTokenIndex;
354
11.9k
                int nSkippedTokens = 0;
355
11.9k
                if( RTF_SWGDEFS & nToken)
356
1.29k
                {
357
1.29k
                    if( RTF_IGNOREFLAG != GetStackPtr( -1 )->nTokenId )
358
128
                        break;
359
1.16k
                    nToken = SkipToken();
360
1.16k
                    ++nSkippedTokens;
361
1.16k
                    if( '{' == GetStackPtr( -1 )->nTokenId )
362
861
                    {
363
861
                        nToken = SkipToken();
364
861
                        ++nSkippedTokens;
365
861
                    }
366
1.16k
                }
367
11.8k
                ReadAttr( nToken, &xStyle->aAttrSet );
368
11.8k
                if (nSkippedTokens && m_nTokenIndex == nEnteringIndex - nSkippedTokens)
369
395
                {
370
                    // we called SkipToken to go back one or two, but ReadAttrs
371
                    // read nothing, so on next loop of the outer while we
372
                    // would end up in the same state again (assert that)
373
395
                    assert(nEnteringToken == GetNextToken());
374
                    // and loop endlessly, skip format a token
375
                    // instead to avoid that
376
395
                    SkipToken(nSkippedTokens);
377
395
                }
378
11.8k
                break;
379
40.8k
            }
380
40.8k
            break;
381
124k
        }
382
124k
    }
383
599
    xStyle.reset();         // Delete the Last Style
384
599
    SkipToken();        // the closing brace is evaluated "above"
385
386
    // Flag back to old state
387
599
    bChkStyleAttr = bSaveChkStyleAttr;
388
599
    bIsInReadStyleTab = false;
389
599
}
390
391
void SvxRTFParser::ReadColorTable()
392
918
{
393
918
    int nToken;
394
918
    sal_uInt8 nRed = 0xff, nGreen = 0xff, nBlue = 0xff;
395
396
918
    for (;;)
397
19.2k
    {
398
19.2k
        nToken = GetNextToken();
399
19.2k
        if ( '}' == nToken || !IsParserWorking() )
400
918
            break;
401
18.3k
        switch( nToken )
402
18.3k
        {
403
2.89k
        case RTF_RED:   nRed = sal_uInt8(nTokenValue);      break;
404
2.86k
        case RTF_GREEN: nGreen = sal_uInt8(nTokenValue);        break;
405
2.81k
        case RTF_BLUE:  nBlue = sal_uInt8(nTokenValue);     break;
406
407
7.64k
        case RTF_TEXTTOKEN:
408
7.64k
            if( 1 == aToken.getLength()
409
7.64k
                    ? aToken[ 0 ] != ';'
410
7.64k
                    : -1 == aToken.indexOf( ";" ) )
411
3.51k
                break;      // At least the ';' must be found
412
413
4.13k
            [[fallthrough]];
414
415
4.13k
        case ';':
416
4.13k
            if( IsParserWorking() )
417
4.13k
            {
418
                // one color is finished, fill in the table
419
                // try to map the values to SV internal names
420
4.13k
                Color aColor( nRed, nGreen, nBlue );
421
4.13k
                if( maColorTable.empty() &&
422
555
                    sal_uInt8(-1) == nRed && sal_uInt8(-1) == nGreen && sal_uInt8(-1) == nBlue )
423
492
                    aColor = COL_AUTO;
424
4.13k
                maColorTable.push_back( aColor );
425
4.13k
                nRed = 0;
426
4.13k
                nGreen = 0;
427
4.13k
                nBlue = 0;
428
429
                // Color has been completely read,
430
                // so this is still a stable status
431
4.13k
                SaveState( RTF_COLORTBL );
432
4.13k
            }
433
4.13k
            break;
434
18.3k
        }
435
18.3k
    }
436
918
    SkipToken();        // the closing brace is evaluated "above"
437
918
}
438
439
void SvxRTFParser::ReadFontTable()
440
1.03k
{
441
1.03k
    int _nOpenBrackets = 1;      // the first was already detected earlier!!
442
1.03k
    vcl::Font aFont;
443
1.03k
    short nFontNo(0), nInsFontNo (0);
444
1.03k
    OUString sAltNm, sFntNm;
445
1.03k
    bool bIsAltFntNm = false;
446
447
1.03k
    rtl_TextEncoding nSystemChar = lcl_GetDefaultTextEncodingForRTF();
448
1.03k
    aFont.SetCharSet( nSystemChar );
449
1.03k
    SetEncoding( nSystemChar );
450
451
95.6k
    while( _nOpenBrackets && IsParserWorking() )
452
94.6k
    {
453
94.6k
        bool bCheckNewFont = false;
454
94.6k
        int nToken = GetNextToken();
455
94.6k
        switch( nToken )
456
94.6k
        {
457
9.89k
            case '}':
458
9.89k
                bIsAltFntNm = false;
459
                // Style has been completely read,
460
                // so this is still a stable status
461
9.89k
                if( --_nOpenBrackets <= 1 && IsParserWorking() )
462
7.06k
                    SaveState( RTF_FONTTBL );
463
9.89k
                bCheckNewFont = true;
464
9.89k
                nInsFontNo = nFontNo;
465
9.89k
                break;
466
27.3k
            case '{':
467
27.3k
                if( RTF_IGNOREFLAG != GetNextToken() )
468
25.3k
                    SkipToken();
469
                // immediately skip unknown and all known but non-evaluated
470
                // groups
471
1.96k
                else if( RTF_UNKNOWNCONTROL != ( nToken = GetNextToken() ) &&
472
1.85k
                        RTF_PANOSE != nToken && RTF_FNAME != nToken &&
473
687
                        RTF_FONTEMB != nToken && RTF_FONTFILE != nToken )
474
687
                    SkipToken( -2 );
475
1.27k
                else
476
1.27k
                {
477
                    // filter out at once
478
1.27k
                    ReadUnknownData();
479
1.27k
                    nToken = GetNextToken();
480
1.27k
                    if( '}' != nToken )
481
13
                        eState = SvParserState::Error;
482
1.27k
                    break;
483
1.27k
                }
484
26.0k
                ++_nOpenBrackets;
485
26.0k
                break;
486
2.24k
            case RTF_FROMAN:
487
2.24k
                aFont.SetFamily( FAMILY_ROMAN );
488
2.24k
                break;
489
1.77k
            case RTF_FSWISS:
490
1.77k
                aFont.SetFamily( FAMILY_SWISS );
491
1.77k
                break;
492
544
            case RTF_FMODERN:
493
544
                aFont.SetFamily( FAMILY_MODERN );
494
544
                break;
495
104
            case RTF_FSCRIPT:
496
104
                aFont.SetFamily( FAMILY_SCRIPT );
497
104
                break;
498
201
            case RTF_FDECOR:
499
201
                aFont.SetFamily( FAMILY_DECORATIVE );
500
201
                break;
501
            // for technical/symbolic font of the rtl_TextEncoding is changed!
502
254
            case RTF_FTECH:
503
254
                aFont.SetCharSet( RTL_TEXTENCODING_SYMBOL );
504
254
                [[fallthrough]];
505
2.08k
            case RTF_FNIL:
506
2.08k
                aFont.SetFamily( FAMILY_DONTKNOW );
507
2.08k
                break;
508
7.53k
            case RTF_FCHARSET:
509
7.53k
                if (-1 != nTokenValue)
510
7.40k
                {
511
7.40k
                    rtl_TextEncoding nrtl_TextEncoding = rtl_getTextEncodingFromWindowsCharset(
512
7.40k
                        static_cast<sal_uInt8>(nTokenValue));
513
7.40k
                    aFont.SetCharSet(nrtl_TextEncoding);
514
                    //When we're in a font, the fontname is in the font
515
                    //charset, except for symbol fonts I believe
516
7.40k
                    if (nrtl_TextEncoding == RTL_TEXTENCODING_SYMBOL)
517
586
                        nrtl_TextEncoding = RTL_TEXTENCODING_DONTKNOW;
518
7.40k
                    SetEncoding(nrtl_TextEncoding);
519
7.40k
                }
520
7.53k
                break;
521
4.61k
            case RTF_FPRQ:
522
4.61k
                switch( nTokenValue )
523
4.61k
                {
524
545
                    case 1:
525
545
                        aFont.SetPitch( PITCH_FIXED );
526
545
                        break;
527
3.42k
                    case 2:
528
3.42k
                        aFont.SetPitch( PITCH_VARIABLE );
529
3.42k
                        break;
530
4.61k
                }
531
4.61k
                break;
532
10.2k
            case RTF_F:
533
10.2k
                bCheckNewFont = true;
534
10.2k
                nInsFontNo = nFontNo;
535
10.2k
                nFontNo = static_cast<short>(nTokenValue);
536
10.2k
                break;
537
655
            case RTF_FALT:
538
655
                bIsAltFntNm = true;
539
655
                break;
540
19.8k
            case RTF_TEXTTOKEN:
541
19.8k
                DelCharAtEnd( aToken, ';' );
542
19.8k
                if ( !aToken.isEmpty() )
543
16.0k
                {
544
16.0k
                    if( bIsAltFntNm )
545
811
                        sAltNm = aToken;
546
15.2k
                    else
547
15.2k
                        sFntNm = aToken;
548
16.0k
                }
549
19.8k
                break;
550
94.6k
        }
551
552
94.6k
        if( bCheckNewFont && 1 >= _nOpenBrackets && !sFntNm.isEmpty() )  // one font is ready
553
7.17k
        {
554
            // All data from the font is available, so off to the table
555
7.17k
            if (!sAltNm.isEmpty())
556
578
                sFntNm += ";" + sAltNm;
557
558
7.17k
            aFont.SetFamilyName( sFntNm );
559
7.17k
            m_FontTable.insert(std::make_pair(nInsFontNo, aFont));
560
7.17k
            aFont = vcl::Font();
561
7.17k
            aFont.SetCharSet( nSystemChar );
562
7.17k
            sAltNm.clear();
563
7.17k
            sFntNm.clear();
564
7.17k
        }
565
94.6k
    }
566
1.03k
    SkipToken();        // the closing brace is evaluated "above"
567
568
    // set the default font in the Document
569
1.03k
    if( bNewDoc && IsParserWorking() )
570
0
        SetDefault( RTF_DEFF, nDfltFont );
571
1.03k
}
572
573
void SvxRTFParser::ClearColorTbl()
574
0
{
575
0
    maColorTable.clear();
576
0
}
577
578
void SvxRTFParser::ClearAttrStack()
579
6.20k
{
580
6.20k
    aAttrStack.clear();
581
6.20k
}
582
583
void SvxRTFParser::DelCharAtEnd( OUStringBuffer& rStr, const sal_Unicode cDel )
584
34.7k
{
585
34.7k
    rStr.strip(' ');
586
34.7k
    if( !rStr.isEmpty() && cDel == rStr[ rStr.getLength()-1 ])
587
12.9k
        rStr.setLength( rStr.getLength()-1 );
588
34.7k
}
589
590
591
const vcl::Font& SvxRTFParser::GetFont( sal_uInt16 nId )
592
62.2k
{
593
62.2k
    SvxRTFFontTbl::const_iterator it = m_FontTable.find( nId );
594
62.2k
    if (it != m_FontTable.end())
595
16.8k
    {
596
16.8k
        return it->second;
597
16.8k
    }
598
45.3k
    const SvxFontItem& rDfltFont =
599
45.3k
        pAttrPool->GetUserOrPoolDefaultItem(aPlainMap[SID_ATTR_CHAR_FONT]);
600
45.3k
    pDfltFont->SetFamilyName( rDfltFont.GetStyleName() );
601
45.3k
    pDfltFont->SetFamily( rDfltFont.GetFamily() );
602
45.3k
    return *pDfltFont;
603
62.2k
}
604
605
std::unique_ptr<SvxRTFItemStackType> SvxRTFItemStackType::createSvxRTFItemStackType(
606
    SfxItemPool& rPool, const WhichRangesContainer& pWhichRange, const EditPosition& rEditPosition)
607
8.28k
{
608
8.28k
    struct MakeUniqueEnabler : public SvxRTFItemStackType
609
8.28k
    {
610
8.28k
        MakeUniqueEnabler(SfxItemPool& rPool, const WhichRangesContainer& pWhichRange, const EditPosition& rEditPosition)
611
8.28k
            : SvxRTFItemStackType(rPool, pWhichRange, rEditPosition)
612
8.28k
        {
613
8.28k
        }
614
8.28k
    };
615
8.28k
    return std::make_unique<MakeUniqueEnabler>(rPool, pWhichRange, rEditPosition);
616
8.28k
}
617
618
SvxRTFItemStackType* SvxRTFParser::GetAttrSet_()
619
92.0k
{
620
92.0k
    SvxRTFItemStackType* pCurrent = aAttrStack.empty() ? nullptr : aAttrStack.back().get();
621
92.0k
    std::unique_ptr<SvxRTFItemStackType> xNew;
622
92.0k
    if( pCurrent )
623
83.7k
        xNew = std::make_unique<SvxRTFItemStackType>(*pCurrent, *mxInsertPosition, false/*bCopyAttr*/);
624
8.28k
    else
625
8.28k
        xNew = SvxRTFItemStackType::createSvxRTFItemStackType(*pAttrPool, aWhichMap, *mxInsertPosition);
626
92.0k
    xNew->SetRTFDefaults( GetRTFDefaults() );
627
628
92.0k
    aAttrStack.push_back( std::move(xNew) );
629
630
92.0k
    if (aAttrStack.size() > 96 && comphelper::IsFuzzing())
631
38
        throw std::range_error("ecStackOverflow");
632
633
91.9k
    bNewGroup = false;
634
91.9k
    return aAttrStack.back().get();
635
92.0k
}
636
637
void SvxRTFParser::ClearStyleAttr_( SvxRTFItemStackType& rStkType )
638
0
{
639
    // check attributes to the attributes of the stylesheet or to
640
    // the default attrs of the document
641
0
    SfxItemSet &rSet = rStkType.GetAttrSet();
642
0
    const SfxItemPool& rPool = *rSet.GetPool();
643
0
    const SfxPoolItem* pItem;
644
0
    SfxWhichIter aIter( rSet );
645
646
0
    if( !IsChkStyleAttr() ||
647
0
        !rStkType.GetAttrSet().Count() ||
648
0
        m_StyleTable.count( rStkType.nStyleNo ) == 0 )
649
0
    {
650
0
        for( sal_uInt16 nWhich = aIter.GetCurWhich(); nWhich; nWhich = aIter.NextWhich() )
651
0
        {
652
0
            if (SfxItemPool::IsWhich(nWhich) &&
653
0
                SfxItemState::SET == aIter.GetItemState( false, &pItem ) &&
654
0
                     rPool.GetUserOrPoolDefaultItem( nWhich ) == *pItem )
655
0
                aIter.ClearItem();       // delete
656
0
        }
657
0
    }
658
0
    else
659
0
    {
660
        // Delete all Attributes, which are already defined in the Style,
661
        // from the current AttrSet.
662
0
        auto & rStyle = m_StyleTable.find(rStkType.nStyleNo)->second;
663
0
        SfxItemSet &rStyleSet = rStyle.aAttrSet;
664
0
        const SfxPoolItem* pSItem;
665
0
        for( sal_uInt16 nWhich = aIter.GetCurWhich(); nWhich; nWhich = aIter.NextWhich() )
666
0
        {
667
0
            if( SfxItemState::SET == rStyleSet.GetItemState( nWhich, true, &pSItem ))
668
0
            {
669
0
                if( SfxItemState::SET == aIter.GetItemState( false, &pItem )
670
0
                    && *pItem == *pSItem )
671
0
                    rSet.ClearItem( nWhich );       // delete
672
0
            }
673
0
            else if (SfxItemPool::IsWhich(nWhich) &&
674
0
                    SfxItemState::SET == aIter.GetItemState( false, &pItem ) &&
675
0
                     rPool.GetUserOrPoolDefaultItem( nWhich ) == *pItem )
676
0
                rSet.ClearItem( nWhich );       // delete
677
0
        }
678
0
    }
679
0
}
680
681
void SvxRTFParser::AttrGroupEnd()   // process the current, delete from Stack
682
139k
{
683
139k
    if( aAttrStack.empty() )
684
5.25k
        return;
685
686
133k
    std::unique_ptr<SvxRTFItemStackType> pOld = std::move(aAttrStack.back());
687
133k
    aAttrStack.pop_back();
688
133k
    SvxRTFItemStackType *pCurrent = aAttrStack.empty() ? nullptr : aAttrStack.back().get();
689
690
133k
    do {        // middle check loop
691
133k
        sal_Int32 nOldSttNdIdx = pOld->mxStartNodeIdx->GetIdx();
692
133k
        if (pOld->maChildList.empty() &&
693
111k
            ((!pOld->aAttrSet.Count() && !pOld->nStyleNo ) ||
694
111k
            (nOldSttNdIdx == mxInsertPosition->GetNodeIdx() &&
695
58.3k
            pOld->nSttCnt == mxInsertPosition->GetCntIdx() )))
696
4.02k
            break;          // no attributes or Area
697
698
        // set only the attributes that are different from the parent
699
129k
        if( pCurrent && pOld->aAttrSet.Count() )
700
86.8k
        {
701
            // ITEM: SfxItemIter and removing SfxPoolItems:
702
            // iterating and clearing Items on the same incarnation is in
703
            // general a bad idea, it invalidates iterators. Work around
704
            // this by remembering the WhichIDs of Items to delete
705
86.8k
            std::vector<sal_uInt16> aDeleteWhichIDs;
706
707
458k
            for (SfxItemIter aIter(pOld->aAttrSet); !aIter.IsAtEnd(); aIter.Next())
708
371k
            {
709
371k
                const SfxPoolItem* pGet(nullptr);
710
371k
                if (SfxItemState::SET == pCurrent->aAttrSet.GetItemState(aIter.GetCurWhich(), false, &pGet)
711
171k
                    && *aIter.GetCurItem() == *pGet)
712
142k
                    aDeleteWhichIDs.push_back(aIter.GetCurWhich());
713
371k
            }
714
715
86.8k
            for (auto nDelWhich : aDeleteWhichIDs)
716
142k
                pOld->aAttrSet.ClearItem(nDelWhich);
717
718
86.8k
            if (!pOld->aAttrSet.Count() && pOld->maChildList.empty() &&
719
18.3k
                !pOld->nStyleNo )
720
16.1k
                break;
721
86.8k
        }
722
723
        // Set all attributes which have been defined from start until here
724
113k
        bool bCrsrBack = !mxInsertPosition->GetCntIdx();
725
113k
        if( bCrsrBack )
726
24.7k
        {
727
            // at the beginning of a paragraph? Move back one position
728
24.7k
            sal_Int32 nNd = mxInsertPosition->GetNodeIdx();
729
24.7k
            MovePos(false);
730
            // if can not move backward then later don't move forward !
731
24.7k
            bCrsrBack = nNd != mxInsertPosition->GetNodeIdx();
732
24.7k
        }
733
734
113k
        if( pOld->mxStartNodeIdx->GetIdx() < mxInsertPosition->GetNodeIdx() ||
735
70.6k
            ( pOld->mxStartNodeIdx->GetIdx() == mxInsertPosition->GetNodeIdx() &&
736
70.6k
              pOld->nSttCnt <= mxInsertPosition->GetCntIdx() ) )
737
113k
        {
738
113k
            if( !bCrsrBack )
739
88.8k
            {
740
                // all pard attributes are only valid until the previous
741
                // paragraph !!
742
88.8k
                if( nOldSttNdIdx == mxInsertPosition->GetNodeIdx() )
743
52.1k
                {
744
52.1k
                }
745
36.6k
                else
746
36.6k
                {
747
                    // Now it gets complicated:
748
                    // - all character attributes sre keep the area
749
                    // - all paragraph attributes to get the area
750
                    //   up to the previous paragraph
751
36.6k
                    auto xNew = std::make_unique<SvxRTFItemStackType>(*pOld, *mxInsertPosition, true);
752
36.6k
                    xNew->aAttrSet.SetParent( pOld->aAttrSet.GetParent() );
753
754
                    // Delete all paragraph attributes from xNew
755
36.6k
                    for (const auto& pair : aPardMap.data)
756
623k
                        if (sal_uInt16 wid = pair.second)
757
476k
                            xNew->aAttrSet.ClearItem(wid);
758
36.6k
                    xNew->SetRTFDefaults( GetRTFDefaults() );
759
760
                    // Were there any?
761
36.6k
                    if( xNew->aAttrSet.Count() == pOld->aAttrSet.Count() )
762
8.85k
                    {
763
8.85k
                        xNew.reset();
764
8.85k
                    }
765
27.8k
                    else
766
27.8k
                    {
767
27.8k
                        xNew->nStyleNo = 0;
768
769
                        // Now span the real area of xNew from old
770
27.8k
                        SetEndPrevPara( pOld->mxEndNodeIdx, pOld->nEndCnt );
771
27.8k
                        xNew->nSttCnt = 0;
772
773
27.8k
                        if( IsChkStyleAttr() )
774
0
                        {
775
0
                            ClearStyleAttr_( *pOld );
776
0
                            ClearStyleAttr_( *xNew );   //#i10381#, methinks.
777
0
                        }
778
779
27.8k
                        if( pCurrent )
780
22.4k
                        {
781
22.4k
                            pCurrent->Add(std::move(pOld));
782
22.4k
                            pCurrent->Add(std::move(xNew));
783
22.4k
                        }
784
5.39k
                        else
785
5.39k
                        {
786
                            // Last off the stack, thus cache it until the next text was
787
                            // read. (Span no attributes!)
788
789
5.39k
                            m_AttrSetList.push_back(std::move(pOld));
790
5.39k
                            m_AttrSetList.push_back(std::move(xNew));
791
5.39k
                        }
792
27.8k
                        break;
793
27.8k
                    }
794
36.6k
                }
795
88.8k
            }
796
797
85.7k
            pOld->mxEndNodeIdx = mxInsertPosition->MakeNodeIdx();
798
85.7k
            pOld->nEndCnt = mxInsertPosition->GetCntIdx();
799
800
            /*
801
            #i21422#
802
            If the parent (pCurrent) sets something e.g. , and the child (pOld)
803
            unsets it and the style both are based on has it unset then
804
            clearing the pOld by looking at the style is clearly a disaster
805
            as the text ends up with pCurrents bold and not pOlds no bold, this
806
            should be rethought out. For the moment its safest to just do
807
            the clean if we have no parent, all we suffer is too many
808
            redundant properties.
809
            */
810
85.7k
            if (IsChkStyleAttr() && !pCurrent)
811
0
                ClearStyleAttr_( *pOld );
812
813
85.7k
            if( pCurrent )
814
48.2k
            {
815
48.2k
                pCurrent->Add(std::move(pOld));
816
                // split up and create new entry, because it makes no sense
817
                // to create a "so long" depend list. Bug 95010
818
48.2k
                if (bCrsrBack && 50 < pCurrent->maChildList.size())
819
187
                {
820
                    // at the beginning of a paragraph? Move back one position
821
187
                    MovePos();
822
187
                    bCrsrBack = false;
823
824
                    // Open a new Group.
825
187
                    auto xNew(std::make_unique<SvxRTFItemStackType>(*pCurrent, *mxInsertPosition, true));
826
187
                    xNew->SetRTFDefaults( GetRTFDefaults() );
827
828
                    // Set all until here valid Attributes
829
187
                    AttrGroupEnd();
830
187
                    pCurrent = aAttrStack.empty() ? nullptr : aAttrStack.back().get();  // can be changed after AttrGroupEnd!
831
187
                    xNew->aAttrSet.SetParent( pCurrent ? &pCurrent->aAttrSet : nullptr );
832
187
                    aAttrStack.push_back( std::move(xNew) );
833
187
                }
834
48.2k
            }
835
37.5k
            else
836
                // Last off the stack, thus cache it until the next text was
837
                // read. (Span no attributes!)
838
37.5k
                m_AttrSetList.push_back(std::move(pOld));
839
85.7k
        }
840
841
85.7k
        if( bCrsrBack )
842
            // at the beginning of a paragraph? Move back one position
843
24.5k
            MovePos();
844
845
85.7k
    } while( false );
846
847
133k
    bNewGroup = false;
848
133k
}
849
850
void SvxRTFParser::SetAllAttrOfStk()        // end all Attr. and set it into doc
851
730
{
852
    // repeat until all attributes will be taken from stack
853
7.02k
    while( !aAttrStack.empty() )
854
6.29k
        AttrGroupEnd();
855
856
1.45k
    for (size_t n = m_AttrSetList.size(); n; )
857
723
    {
858
723
        auto const& pStkSet = m_AttrSetList[--n];
859
723
        SetAttrSet( *pStkSet );
860
723
        pStkSet->DropChildList();
861
723
        m_AttrSetList.pop_back();
862
723
    }
863
730
}
864
865
// sets all the attributes that are different from the current
866
void SvxRTFParser::SetAttrSet( SvxRTFItemStackType &rSet )
867
99.8k
{
868
    // Was DefTab never read? then set to default
869
99.8k
    if( !bIsSetDfltTab )
870
99.8k
        SetDefault( RTF_DEFTAB, 720 );
871
872
99.8k
    if (!rSet.maChildList.empty())
873
19.7k
        rSet.Compress( *this );
874
99.8k
    if( rSet.aAttrSet.Count() || rSet.nStyleNo )
875
92.2k
        SetAttrInDoc( rSet );
876
877
    // then process all the children
878
152k
    for (size_t n = 0; n < rSet.maChildList.size(); ++n)
879
52.2k
        SetAttrSet( *(rSet.maChildList[ n ]) );
880
99.8k
}
881
882
// Has no text been inserted yet? (SttPos from the top Stack entry!)
883
bool SvxRTFParser::IsAttrSttPos()
884
29.2k
{
885
29.2k
    SvxRTFItemStackType* pCurrent = aAttrStack.empty() ? nullptr : aAttrStack.back().get();
886
29.2k
    return !pCurrent || (pCurrent->mxStartNodeIdx->GetIdx() == mxInsertPosition->GetNodeIdx() &&
887
24.7k
        pCurrent->nSttCnt == mxInsertPosition->GetCntIdx());
888
29.2k
}
889
890
891
void SvxRTFParser::SetAttrInDoc( SvxRTFItemStackType & )
892
0
{
893
0
}
894
895
void SvxRTFParser::BuildWhichTable()
896
10.9k
{
897
10.9k
    aWhichMap.reset();
898
899
    // Here are the IDs for all paragraph attributes, which can be detected by
900
    // SvxParser and can be set in a SfxItemSet. The IDs are set correctly through
901
    // the SlotIds from POOL.
902
10.9k
    static constexpr sal_uInt16 WIDS1[] {
903
10.9k
             SID_ATTR_PARA_LINESPACE,
904
10.9k
             SID_ATTR_PARA_ADJUST,
905
10.9k
             SID_ATTR_TABSTOP,
906
10.9k
             SID_ATTR_PARA_HYPHENZONE,
907
10.9k
             SID_ATTR_LRSPACE,
908
10.9k
             SID_ATTR_ULSPACE,
909
10.9k
             SID_ATTR_BRUSH,
910
10.9k
             SID_ATTR_BORDER_OUTER,
911
10.9k
             SID_ATTR_BORDER_SHADOW,
912
10.9k
             SID_ATTR_PARA_OUTLLEVEL,
913
10.9k
             SID_ATTR_PARA_SPLIT,
914
10.9k
             SID_ATTR_PARA_KEEP,
915
10.9k
             SID_PARA_VERTALIGN,
916
10.9k
             SID_ATTR_PARA_SCRIPTSPACE,
917
10.9k
             SID_ATTR_PARA_HANGPUNCTUATION,
918
10.9k
             SID_ATTR_PARA_FORBIDDEN_RULES,
919
10.9k
             SID_ATTR_FRAMEDIRECTION,
920
10.9k
         };
921
10.9k
    for (sal_uInt16 nWid : WIDS1)
922
185k
    {
923
185k
        sal_uInt16 nTrueWid = pAttrPool->GetTrueWhichIDFromSlotID(nWid, false);
924
185k
        aPardMap.data[nWid] = nTrueWid;
925
185k
        if (nTrueWid == 0)
926
76.4k
            continue;
927
109k
        aWhichMap = aWhichMap.MergeRange(nTrueWid, nTrueWid);
928
109k
    }
929
930
    // Here are the IDs for all character attributes, which can be detected by
931
    // SvxParser and can be set in a SfxItemSet. The IDs are set correctly through
932
    // the SlotIds from POOL.
933
10.9k
    static constexpr sal_uInt16 WIDS[] {
934
10.9k
             SID_ATTR_CHAR_CASEMAP,        SID_ATTR_BRUSH_CHAR,        SID_ATTR_CHAR_COLOR,
935
10.9k
             SID_ATTR_CHAR_CONTOUR,        SID_ATTR_CHAR_STRIKEOUT,    SID_ATTR_CHAR_ESCAPEMENT,
936
10.9k
             SID_ATTR_CHAR_FONT,           SID_ATTR_CHAR_FONTHEIGHT,   SID_ATTR_CHAR_KERNING,
937
10.9k
             SID_ATTR_CHAR_LANGUAGE,       SID_ATTR_CHAR_POSTURE,      SID_ATTR_CHAR_SHADOWED,
938
10.9k
             SID_ATTR_CHAR_UNDERLINE,      SID_ATTR_CHAR_OVERLINE,     SID_ATTR_CHAR_WEIGHT,
939
10.9k
             SID_ATTR_CHAR_WORDLINEMODE,   SID_ATTR_CHAR_AUTOKERN,     SID_ATTR_CHAR_CJK_FONT,
940
10.9k
             SID_ATTR_CHAR_CJK_FONTHEIGHT, sal_uInt16(SID_ATTR_CHAR_CJK_LANGUAGE), SID_ATTR_CHAR_CJK_POSTURE,
941
10.9k
             SID_ATTR_CHAR_CJK_WEIGHT,     SID_ATTR_CHAR_CTL_FONT,     SID_ATTR_CHAR_CTL_FONTHEIGHT,
942
10.9k
             SID_ATTR_CHAR_CTL_LANGUAGE,   SID_ATTR_CHAR_CTL_POSTURE,  SID_ATTR_CHAR_CTL_WEIGHT,
943
10.9k
             SID_ATTR_CHAR_EMPHASISMARK,   SID_ATTR_CHAR_TWO_LINES,    SID_ATTR_CHAR_SCALEWIDTH,
944
10.9k
             SID_ATTR_CHAR_ROTATED,        SID_ATTR_CHAR_RELIEF,       SID_ATTR_CHAR_HIDDEN,
945
10.9k
         };
946
10.9k
    for (sal_uInt16 nWid : WIDS)
947
360k
    {
948
360k
        sal_uInt16 nTrueWid = pAttrPool->GetTrueWhichIDFromSlotID(nWid, false);
949
360k
        aPlainMap.data[nWid] = nTrueWid;
950
360k
        if (nTrueWid == 0)
951
43.7k
            continue;
952
316k
        aWhichMap = aWhichMap.MergeRange(nTrueWid, nTrueWid);
953
316k
    }
954
10.9k
}
955
956
const SfxItemSet& SvxRTFParser::GetRTFDefaults()
957
253k
{
958
253k
    if( !pRTFDefaults )
959
7.16k
    {
960
7.16k
        pRTFDefaults.reset(new SfxItemSet(*pAttrPool, aWhichMap));
961
7.16k
        if (const sal_uInt16 nId = aPardMap[SID_ATTR_PARA_SCRIPTSPACE])
962
7.16k
        {
963
7.16k
            SvxScriptSpaceItem aItem( false, nId );
964
7.16k
            if( bNewDoc )
965
0
                pAttrPool->SetUserDefaultItem( aItem );
966
7.16k
            else
967
7.16k
                pRTFDefaults->Put( aItem );
968
7.16k
        }
969
7.16k
    }
970
253k
    return *pRTFDefaults;
971
253k
}
972
973
974
SvxRTFStyleType::SvxRTFStyleType(SfxItemPool& rPool, const WhichRangesContainer& pWhichRange)
975
15.4k
    : aAttrSet(rPool, pWhichRange)
976
15.4k
    , nBasedOn(0)
977
15.4k
    , nOutlineNo(sal_uInt8(-1))         // not set
978
15.4k
{
979
15.4k
}
980
981
SvxRTFItemStackType::SvxRTFItemStackType(
982
        SfxItemPool& rPool, const WhichRangesContainer& pWhichRange,
983
        const EditPosition& rPos )
984
8.28k
    : aAttrSet( rPool, pWhichRange )
985
8.28k
    , mxStartNodeIdx(rPos.MakeNodeIdx())
986
8.28k
    , mxEndNodeIdx(mxStartNodeIdx)
987
8.28k
    , nSttCnt(rPos.GetCntIdx())
988
8.28k
    , nEndCnt(nSttCnt)
989
8.28k
    , nStyleNo(0)
990
8.28k
{
991
8.28k
}
992
993
SvxRTFItemStackType::SvxRTFItemStackType(
994
        const SvxRTFItemStackType& rCpy,
995
        const EditPosition& rPos,
996
        bool const bCopyAttr )
997
215k
    : aAttrSet( *rCpy.aAttrSet.GetPool(), rCpy.aAttrSet.GetRanges() )
998
215k
    , mxStartNodeIdx(rPos.MakeNodeIdx())
999
215k
    , mxEndNodeIdx(mxStartNodeIdx)
1000
215k
    , nSttCnt(rPos.GetCntIdx())
1001
215k
    , nEndCnt(nSttCnt)
1002
215k
    , nStyleNo(rCpy.nStyleNo)
1003
215k
{
1004
215k
    aAttrSet.SetParent( &rCpy.aAttrSet );
1005
215k
    if( bCopyAttr )
1006
131k
        aAttrSet.Put( rCpy.aAttrSet );
1007
215k
}
1008
1009
/* ofz#13491 SvxRTFItemStackType dtor recursively
1010
   calls the dtor of its m_pChildList. The recurse
1011
   depth can grow sufficiently to trigger asan.
1012
1013
   So breadth-first iterate through the nodes
1014
   and make a flat vector of them which can
1015
   be iterated through in order of most
1016
   distant from root first and release
1017
   their children linearly
1018
*/
1019
void SvxRTFItemStackType::DropChildList()
1020
723
{
1021
723
    if (maChildList.empty())
1022
353
        return;
1023
1024
370
    std::vector<SvxRTFItemStackType*> bfs;
1025
370
    std::queue<SvxRTFItemStackType*> aQueue;
1026
370
    aQueue.push(this);
1027
1028
32.0k
    while (!aQueue.empty())
1029
31.7k
    {
1030
31.7k
        auto* front = aQueue.front();
1031
31.7k
        aQueue.pop();
1032
31.7k
        if (!front->maChildList.empty())
1033
8.03k
        {
1034
8.03k
            for (const auto& a : front->maChildList)
1035
31.3k
                aQueue.push(a.get());
1036
8.03k
            bfs.push_back(front);
1037
8.03k
        }
1038
31.7k
    }
1039
1040
8.40k
    for (auto it = bfs.rbegin(); it != bfs.rend(); ++it)
1041
8.03k
    {
1042
8.03k
        SvxRTFItemStackType* pNode = *it;
1043
8.03k
        pNode->maChildList.clear();
1044
8.03k
    }
1045
370
}
1046
1047
SvxRTFItemStackType::~SvxRTFItemStackType()
1048
223k
{
1049
223k
}
1050
1051
void SvxRTFItemStackType::Add(std::unique_ptr<SvxRTFItemStackType> pIns)
1052
93.0k
{
1053
93.0k
    maChildList.push_back(std::move(pIns));
1054
93.0k
}
1055
1056
void SvxRTFItemStackType::SetStartPos( const EditPosition& rPos )
1057
0
{
1058
0
    mxStartNodeIdx = rPos.MakeNodeIdx();
1059
0
    mxEndNodeIdx = mxStartNodeIdx;
1060
0
    nSttCnt = rPos.GetCntIdx();
1061
0
}
1062
1063
void SvxRTFItemStackType::Compress( const SvxRTFParser& rParser )
1064
45.3k
{
1065
45.3k
    ENSURE_OR_RETURN_VOID(!maChildList.empty(), "Compress: ChildList empty");
1066
1067
45.3k
    SvxRTFItemStackType* pTmp = maChildList[0].get();
1068
1069
45.3k
    if( !pTmp->aAttrSet.Count() ||
1070
33.2k
        mxStartNodeIdx->GetIdx() != pTmp->mxStartNodeIdx->GetIdx() ||
1071
32.6k
        nSttCnt != pTmp->nSttCnt )
1072
15.2k
        return;
1073
1074
30.0k
    EditNodeIdx aLastNd = *pTmp->mxEndNodeIdx;
1075
30.0k
    sal_Int32 nLastCnt = pTmp->nEndCnt;
1076
1077
30.0k
    SfxItemSet aMrgSet( pTmp->aAttrSet );
1078
60.1k
    for (size_t n = 1; n < maChildList.size(); ++n)
1079
50.8k
    {
1080
50.8k
        pTmp = maChildList[n].get();
1081
50.8k
        if (!pTmp->maChildList.empty())
1082
17.9k
            pTmp->Compress( rParser );
1083
1084
50.8k
        if( !pTmp->nSttCnt
1085
50.8k
            ? (aLastNd.GetIdx() != pTmp->mxStartNodeIdx->GetIdx() - 1 ||
1086
24.4k
               !rParser.IsEndPara( &aLastNd, nLastCnt ) )
1087
50.8k
            : ( pTmp->nSttCnt != nLastCnt ||
1088
6.28k
                aLastNd.GetIdx() != pTmp->mxStartNodeIdx->GetIdx() ))
1089
20.3k
        {
1090
64.5k
            while (++n < maChildList.size())
1091
44.2k
            {
1092
44.2k
                pTmp = maChildList[n].get();
1093
44.2k
                if (!pTmp->maChildList.empty())
1094
7.67k
                    pTmp->Compress( rParser );
1095
44.2k
            }
1096
20.3k
            return;
1097
20.3k
        }
1098
1099
30.4k
        if( n )
1100
30.4k
        {
1101
            // Search for all which are set over the whole area
1102
            // ITEM: SfxItemIter and removing SfxPoolItems:
1103
30.4k
            std::vector<sal_uInt16> aDeleteWhichIDs;
1104
1105
141k
            for (SfxItemIter aIter(aMrgSet); !aIter.IsAtEnd(); aIter.Next())
1106
111k
            {
1107
111k
                const SfxPoolItem* pGet(nullptr);
1108
111k
                if (SfxItemState::SET != pTmp->aAttrSet.GetItemState(aIter.GetCurWhich(), false, &pGet)
1109
109k
                    || *aIter.GetCurItem() != *pGet)
1110
3.17k
                    aDeleteWhichIDs.push_back(aIter.GetCurWhich());
1111
111k
            }
1112
1113
30.4k
            for (auto nDelWhich : aDeleteWhichIDs)
1114
3.17k
                aMrgSet.ClearItem(nDelWhich);
1115
1116
30.4k
            if( !aMrgSet.Count() )
1117
436
                return;
1118
30.4k
        }
1119
1120
30.0k
        aLastNd = *pTmp->mxEndNodeIdx;
1121
30.0k
        nLastCnt = pTmp->nEndCnt;
1122
30.0k
    }
1123
1124
9.27k
    if( mxEndNodeIdx->GetIdx() != aLastNd.GetIdx() || nEndCnt != nLastCnt )
1125
6.42k
        return;
1126
1127
    // It can be merged
1128
2.85k
    aAttrSet.Put( aMrgSet );
1129
1130
2.85k
    size_t n = 0, nChildLen = maChildList.size();
1131
13.6k
    while (n < nChildLen)
1132
10.8k
    {
1133
10.8k
        pTmp = maChildList[n].get();
1134
10.8k
        pTmp->aAttrSet.Differentiate( aMrgSet );
1135
1136
10.8k
        if (pTmp->maChildList.empty() && !pTmp->aAttrSet.Count() && !pTmp->nStyleNo)
1137
6.61k
        {
1138
6.61k
            maChildList.erase( maChildList.begin() + n );
1139
6.61k
            --nChildLen;
1140
6.61k
            continue;
1141
6.61k
        }
1142
4.19k
        ++n;
1143
4.19k
    }
1144
2.85k
}
1145
void SvxRTFItemStackType::SetRTFDefaults( const SfxItemSet& rDefaults )
1146
223k
{
1147
223k
    if( rDefaults.Count() )
1148
223k
    {
1149
447k
        for (SfxItemIter aIter( rDefaults ); !aIter.IsAtEnd(); aIter.Next())
1150
223k
        {
1151
223k
            const SfxPoolItem* pItem = aIter.GetCurItem();
1152
223k
            sal_uInt16 nWhich = pItem->Which();
1153
223k
            if( SfxItemState::SET != aAttrSet.GetItemState( nWhich, false ))
1154
128k
                aAttrSet.Put(*pItem);
1155
223k
        }
1156
223k
    }
1157
223k
}
1158
1159
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */