Coverage Report

Created: 2025-12-31 10:39

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
934
{
46
47
934
    OUString aLangString( Application::GetSettings().GetLanguageTag().getLanguage());
48
49
934
    if ( aLangString == "ru" || aLangString == "uk" )
50
0
        return RTL_TEXTENCODING_MS_1251;
51
934
    if ( aLangString == "tr" )
52
0
        return RTL_TEXTENCODING_MS_1254;
53
934
    else
54
934
        return RTL_TEXTENCODING_MS_1252;
55
934
}
56
57
// -------------- Methods --------------------
58
59
SvxRTFParser::SvxRTFParser( SfxItemPool& rPool, SvStream& rIn )
60
9.83k
    : SvRTFParser( rIn, 5 )
61
9.83k
    , pAttrPool( &rPool )
62
9.83k
    , nDfltFont( 0)
63
9.83k
    , bNewDoc( true )
64
9.83k
    , bNewGroup( false)
65
9.83k
    , bIsSetDfltTab( false)
66
9.83k
    , bChkStyleAttr( false )
67
9.83k
    , bCalcValue( false )
68
9.83k
    , bIsLeftToRightDef( true)
69
9.83k
    , bIsInReadStyleTab( false)
70
9.83k
{
71
9.83k
    pDfltFont.emplace();
72
9.83k
    mxDefaultColor = Color();
73
74
    // generate the correct WhichId table from the set WhichIds.
75
9.83k
    BuildWhichTable();
76
9.83k
}
77
78
SvxRTFParser::~SvxRTFParser()
79
9.83k
{
80
9.83k
    if( !aAttrStack.empty() )
81
5.56k
        ClearAttrStack();
82
9.83k
}
83
84
void SvxRTFParser::SetInsPos( const EditPosition& rNew )
85
9.83k
{
86
9.83k
    mxInsertPosition = rNew;
87
9.83k
}
88
89
SvParserState SvxRTFParser::CallParser()
90
9.83k
{
91
9.83k
    DBG_ASSERT( mxInsertPosition, "no insertion position");
92
93
9.83k
    if( !mxInsertPosition )
94
0
        return SvParserState::Error;
95
96
9.83k
    if( !maColorTable.empty() )
97
0
        ClearColorTbl();
98
9.83k
    m_FontTable.clear();
99
9.83k
    m_StyleTable.clear();
100
9.83k
    if( !aAttrStack.empty() )
101
0
        ClearAttrStack();
102
103
9.83k
    bIsSetDfltTab = false;
104
9.83k
    bNewGroup = false;
105
9.83k
    nDfltFont = 0;
106
107
9.83k
    return SvRTFParser::CallParser();
108
9.83k
}
109
110
void SvxRTFParser::Continue( int nToken )
111
9.68k
{
112
9.68k
    SvRTFParser::Continue( nToken );
113
114
9.68k
    SvParserState eStatus = GetStatus();
115
9.68k
    if (eStatus != SvParserState::Pending && eStatus != SvParserState::Error)
116
642
    {
117
642
        SetAllAttrOfStk();
118
    //Regardless of what "color 0" is, word defaults to auto as the default colour.
119
    //e.g. see #i7713#
120
642
    }
121
9.68k
}
122
123
124
// is called for each token that is recognized in CallParser
125
void SvxRTFParser::NextToken( int nToken )
126
1.52M
{
127
1.52M
    sal_Unicode cCh;
128
1.52M
    switch( nToken )
129
1.52M
    {
130
874
    case RTF_COLORTBL:      ReadColorTable();       break;
131
934
    case RTF_FONTTBL:       ReadFontTable();        break;
132
588
    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
331
    case RTF_DEFLANG:
148
331
            if( bNewDoc )
149
0
                SetDefault( nToken, nTokenValue );
150
331
            break;
151
152
153
32
    case RTF_PICT:          ReadBitmapData();       break;
154
155
0
    case RTF_LINE:          cCh = '\n'; goto INSINGLECHAR;
156
4.34k
    case RTF_TAB:           cCh = '\t'; goto INSINGLECHAR;
157
1.75k
    case RTF_SUBENTRYINDEX: cCh = ':';  goto INSINGLECHAR;
158
159
71
    case RTF_EMDASH:        cCh = 0x2014;   goto INSINGLECHAR;
160
428
    case RTF_ENDASH:        cCh = 0x2013;   goto INSINGLECHAR;
161
90
    case RTF_BULLET:        cCh = 0x2022;   goto INSINGLECHAR;
162
25
    case RTF_LQUOTE:        cCh = 0x2018;   goto INSINGLECHAR;
163
137
    case RTF_RQUOTE:        cCh = 0x2019;   goto INSINGLECHAR;
164
77
    case RTF_LDBLQUOTE:     cCh = 0x201C;   goto INSINGLECHAR;
165
279
    case RTF_RDBLQUOTE:     cCh = 0x201D;   goto INSINGLECHAR;
166
7.20k
INSINGLECHAR:
167
7.20k
        aToken = OUStringChar(cCh);
168
7.20k
        [[fallthrough]]; // aToken is set as Text
169
890k
    case RTF_TEXTTOKEN:
170
890k
        {
171
890k
            InsertText();
172
            // all collected Attributes are set
173
931k
            for (size_t n = m_AttrSetList.size(); n; )
174
40.5k
            {
175
40.5k
                auto const& pStkSet = m_AttrSetList[--n];
176
40.5k
                SetAttrSet( *pStkSet );
177
40.5k
                m_AttrSetList.pop_back();
178
40.5k
            }
179
890k
        }
180
890k
        break;
181
182
183
300k
    case RTF_PAR:
184
300k
        InsertPara();
185
300k
        break;
186
92.2k
    case '{':
187
92.2k
        if (bNewGroup)          // Nesting!
188
49.1k
            GetAttrSet_();
189
92.2k
        bNewGroup = true;
190
92.2k
        break;
191
46.5k
    case '}':
192
46.5k
        if( !bNewGroup )        // Empty Group ??
193
32.3k
            AttrGroupEnd();
194
46.5k
        bNewGroup = false;
195
46.5k
        break;
196
216
    case RTF_INFO:
197
216
        SkipGroup();
198
216
        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
39
    case RTF_ANNOTATION:
209
210
187
    case RTF_BKMKSTART:
211
326
    case RTF_BKMKEND:
212
326
    case RTF_BKMK_KEY:
213
350
    case RTF_XE:
214
361
    case RTF_TC:
215
361
    case RTF_NEXTFILE:
216
363
    case RTF_TEMPLATE:
217
    // RTF_SHPRSLT disabled for #i19718#
218
363
                            SkipGroup();
219
363
                            break;
220
    // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
221
222
140
    case RTF_PGDSCNO:
223
140
    case RTF_PGBRK:
224
494
    case RTF_SHADOW:
225
494
            if( RTF_IGNOREFLAG != GetStackPtr( -1 )->nTokenId )
226
27
                break;
227
467
            nToken = SkipToken();
228
467
            if( '{' == GetStackPtr( -1 )->nTokenId )
229
248
                nToken = SkipToken();
230
231
467
            ReadAttr( nToken, &GetAttrSet() );
232
467
            break;
233
234
189k
    default:
235
189k
        switch( nToken & ~(0xff | RTF_SWGDEFS) )
236
189k
        {
237
42.3k
        case RTF_PARFMT:        // here are no SWGDEFS
238
42.3k
            ReadAttr( nToken, &GetAttrSet() );
239
42.3k
            break;
240
241
66.6k
        case RTF_CHRFMT:
242
69.3k
        case RTF_BRDRDEF:
243
72.1k
        case RTF_TABSTOPDEF:
244
245
72.1k
            if( RTF_SWGDEFS & nToken)
246
394
            {
247
394
                if( RTF_IGNOREFLAG != GetStackPtr( -1 )->nTokenId )
248
91
                    break;
249
303
                nToken = SkipToken();
250
303
                if( '{' == GetStackPtr( -1 )->nTokenId )
251
299
                {
252
299
                    nToken = SkipToken();
253
299
                }
254
303
            }
255
72.0k
            ReadAttr( nToken, &GetAttrSet() );
256
72.0k
            break;
257
75.4k
        default:
258
75.4k
            {
259
75.4k
                if( RTF_IGNOREFLAG == GetStackPtr( -1 )->nTokenId &&
260
1.22k
                      '{' == GetStackPtr( -2 )->nTokenId )
261
1.08k
                    SkipGroup();
262
75.4k
            }
263
75.4k
            break;
264
189k
        }
265
189k
        break;
266
1.52M
    }
267
1.52M
}
268
269
void SvxRTFParser::ReadStyleTable()
270
588
{
271
588
    int bSaveChkStyleAttr = bChkStyleAttr ? 1 : 0;
272
588
    sal_uInt16 nStyleNo = 0;
273
588
    bool bHasStyleNo = false;
274
588
    int _nOpenBrackets = 1;      // the first was already detected earlier!!
275
588
    std::optional<SvxRTFStyleType> xStyle(SvxRTFStyleType(*pAttrPool, aWhichMap));
276
588
    xStyle->aAttrSet.Put( GetRTFDefaults() );
277
278
588
    bIsInReadStyleTab = true;
279
588
    bChkStyleAttr = false;      // Do not check Attribute against the Styles
280
281
102k
    while( _nOpenBrackets && IsParserWorking() )
282
101k
    {
283
101k
        int nToken = GetNextToken();
284
101k
        switch( nToken )
285
101k
        {
286
6.99k
        case '}':       if( --_nOpenBrackets && IsParserWorking() )
287
                            // Style has been completely read,
288
                            // so this is still a stable status
289
6.70k
                            SaveState( RTF_STYLESHEET );
290
6.99k
                        break;
291
15.2k
        case '{':
292
15.2k
            {
293
15.2k
                if( RTF_IGNOREFLAG != GetNextToken() )
294
12.9k
                    SkipToken();
295
2.30k
                else if( RTF_UNKNOWNCONTROL != ( nToken = GetNextToken() ) &&
296
2.18k
                            RTF_PN != nToken )
297
2.14k
                    SkipToken( -2 );
298
155
                else
299
155
                {
300
                    // filter out at once
301
155
                    ReadUnknownData();
302
155
                    nToken = GetNextToken();
303
155
                    if( '}' != nToken )
304
8
                        eState = SvParserState::Error;
305
155
                    break;
306
155
                }
307
15.1k
                ++_nOpenBrackets;
308
15.1k
            }
309
0
            break;
310
311
2.62k
        case RTF_SBASEDON:  xStyle->nBasedOn = sal_uInt16(nTokenValue); break;
312
3.31k
        case RTF_SNEXT:     break;
313
267
        case RTF_OUTLINELEVEL:
314
327
        case RTF_SOUTLVL:   xStyle->nOutlineNo = sal_uInt8(nTokenValue);    break;
315
11.7k
        case RTF_S:         nStyleNo = static_cast<short>(nTokenValue);
316
11.7k
                            bHasStyleNo = true;
317
11.7k
                            break;
318
1.48k
        case RTF_CS:        nStyleNo = static_cast<short>(nTokenValue);
319
1.48k
                            bHasStyleNo = true;
320
1.48k
                            break;
321
322
31.6k
        case RTF_TEXTTOKEN:
323
31.6k
            if (bHasStyleNo)
324
12.6k
            {
325
12.6k
                DelCharAtEnd( aToken, ';' );
326
12.6k
                xStyle->sName = aToken.toString();
327
328
12.6k
                if (!m_StyleTable.empty())
329
12.1k
                {
330
12.1k
                    m_StyleTable.erase(nStyleNo);
331
12.1k
                }
332
                // All data from the font is available, so off to the table
333
12.6k
                m_StyleTable.emplace(nStyleNo, std::move(*xStyle));
334
12.6k
                xStyle.emplace(*pAttrPool, aWhichMap);
335
12.6k
                xStyle->aAttrSet.Put( GetRTFDefaults() );
336
12.6k
                nStyleNo = 0;
337
12.6k
                bHasStyleNo = false;
338
12.6k
            }
339
31.6k
            break;
340
28.4k
        default:
341
28.4k
            switch( nToken & ~(0xff | RTF_SWGDEFS) )
342
28.4k
            {
343
5.96k
            case RTF_PARFMT:        // here are no SWGDEFS
344
5.96k
                ReadAttr( nToken, &xStyle->aAttrSet );
345
5.96k
                break;
346
347
7.00k
            case RTF_CHRFMT:
348
7.27k
            case RTF_BRDRDEF:
349
8.45k
            case RTF_TABSTOPDEF:
350
#ifndef NDEBUG
351
                auto nEnteringToken = nToken;
352
#endif
353
8.45k
                auto nEnteringIndex = m_nTokenIndex;
354
8.45k
                int nSkippedTokens = 0;
355
8.45k
                if( RTF_SWGDEFS & nToken)
356
714
                {
357
714
                    if( RTF_IGNOREFLAG != GetStackPtr( -1 )->nTokenId )
358
61
                        break;
359
653
                    nToken = SkipToken();
360
653
                    ++nSkippedTokens;
361
653
                    if( '{' == GetStackPtr( -1 )->nTokenId )
362
490
                    {
363
490
                        nToken = SkipToken();
364
490
                        ++nSkippedTokens;
365
490
                    }
366
653
                }
367
8.39k
                ReadAttr( nToken, &xStyle->aAttrSet );
368
8.39k
                if (nSkippedTokens && m_nTokenIndex == nEnteringIndex - nSkippedTokens)
369
209
                {
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
209
                    assert(nEnteringToken == GetNextToken());
374
                    // and loop endlessly, skip format a token
375
                    // instead to avoid that
376
209
                    SkipToken(nSkippedTokens);
377
209
                }
378
8.39k
                break;
379
28.4k
            }
380
28.4k
            break;
381
101k
        }
382
101k
    }
383
588
    xStyle.reset();         // Delete the Last Style
384
588
    SkipToken();        // the closing brace is evaluated "above"
385
386
    // Flag back to old state
387
588
    bChkStyleAttr = bSaveChkStyleAttr;
388
588
    bIsInReadStyleTab = false;
389
588
}
390
391
void SvxRTFParser::ReadColorTable()
392
874
{
393
874
    int nToken;
394
874
    sal_uInt8 nRed = 0xff, nGreen = 0xff, nBlue = 0xff;
395
396
874
    for (;;)
397
20.8k
    {
398
20.8k
        nToken = GetNextToken();
399
20.8k
        if ( '}' == nToken || !IsParserWorking() )
400
874
            break;
401
19.9k
        switch( nToken )
402
19.9k
        {
403
3.24k
        case RTF_RED:   nRed = sal_uInt8(nTokenValue);      break;
404
3.21k
        case RTF_GREEN: nGreen = sal_uInt8(nTokenValue);        break;
405
3.19k
        case RTF_BLUE:  nBlue = sal_uInt8(nTokenValue);     break;
406
407
8.20k
        case RTF_TEXTTOKEN:
408
8.20k
            if( 1 == aToken.getLength()
409
8.20k
                    ? aToken[ 0 ] != ';'
410
8.20k
                    : -1 == aToken.indexOf( ";" ) )
411
3.70k
                break;      // At least the ';' must be found
412
413
4.50k
            [[fallthrough]];
414
415
4.50k
        case ';':
416
4.50k
            if( IsParserWorking() )
417
4.50k
            {
418
                // one color is finished, fill in the table
419
                // try to map the values to SV internal names
420
4.50k
                Color aColor( nRed, nGreen, nBlue );
421
4.50k
                if( maColorTable.empty() &&
422
607
                    sal_uInt8(-1) == nRed && sal_uInt8(-1) == nGreen && sal_uInt8(-1) == nBlue )
423
542
                    aColor = COL_AUTO;
424
4.50k
                maColorTable.push_back( aColor );
425
4.50k
                nRed = 0;
426
4.50k
                nGreen = 0;
427
4.50k
                nBlue = 0;
428
429
                // Color has been completely read,
430
                // so this is still a stable status
431
4.50k
                SaveState( RTF_COLORTBL );
432
4.50k
            }
433
4.50k
            break;
434
19.9k
        }
435
19.9k
    }
436
874
    SkipToken();        // the closing brace is evaluated "above"
437
874
}
438
439
void SvxRTFParser::ReadFontTable()
440
934
{
441
934
    int _nOpenBrackets = 1;      // the first was already detected earlier!!
442
934
    vcl::Font aFont;
443
934
    short nFontNo(0), nInsFontNo (0);
444
934
    OUString sAltNm, sFntNm;
445
934
    bool bIsAltFntNm = false;
446
447
934
    rtl_TextEncoding nSystemChar = lcl_GetDefaultTextEncodingForRTF();
448
934
    aFont.SetCharSet( nSystemChar );
449
934
    SetEncoding( nSystemChar );
450
451
72.7k
    while( _nOpenBrackets && IsParserWorking() )
452
71.8k
    {
453
71.8k
        bool bCheckNewFont = false;
454
71.8k
        int nToken = GetNextToken();
455
71.8k
        switch( nToken )
456
71.8k
        {
457
8.65k
            case '}':
458
8.65k
                bIsAltFntNm = false;
459
                // Style has been completely read,
460
                // so this is still a stable status
461
8.65k
                if( --_nOpenBrackets <= 1 && IsParserWorking() )
462
7.23k
                    SaveState( RTF_FONTTBL );
463
8.65k
                bCheckNewFont = true;
464
8.65k
                nInsFontNo = nFontNo;
465
8.65k
                break;
466
16.8k
            case '{':
467
16.8k
                if( RTF_IGNOREFLAG != GetNextToken() )
468
15.1k
                    SkipToken();
469
                // immediately skip unknown and all known but non-evaluated
470
                // groups
471
1.77k
                else if( RTF_UNKNOWNCONTROL != ( nToken = GetNextToken() ) &&
472
1.67k
                        RTF_PANOSE != nToken && RTF_FNAME != nToken &&
473
582
                        RTF_FONTEMB != nToken && RTF_FONTFILE != nToken )
474
582
                    SkipToken( -2 );
475
1.18k
                else
476
1.18k
                {
477
                    // filter out at once
478
1.18k
                    ReadUnknownData();
479
1.18k
                    nToken = GetNextToken();
480
1.18k
                    if( '}' != nToken )
481
10
                        eState = SvParserState::Error;
482
1.18k
                    break;
483
1.18k
                }
484
15.6k
                ++_nOpenBrackets;
485
15.6k
                break;
486
2.08k
            case RTF_FROMAN:
487
2.08k
                aFont.SetFamily( FAMILY_ROMAN );
488
2.08k
                break;
489
1.61k
            case RTF_FSWISS:
490
1.61k
                aFont.SetFamily( FAMILY_SWISS );
491
1.61k
                break;
492
487
            case RTF_FMODERN:
493
487
                aFont.SetFamily( FAMILY_MODERN );
494
487
                break;
495
78
            case RTF_FSCRIPT:
496
78
                aFont.SetFamily( FAMILY_SCRIPT );
497
78
                break;
498
119
            case RTF_FDECOR:
499
119
                aFont.SetFamily( FAMILY_DECORATIVE );
500
119
                break;
501
            // for technical/symbolic font of the rtl_TextEncoding is changed!
502
58
            case RTF_FTECH:
503
58
                aFont.SetCharSet( RTL_TEXTENCODING_SYMBOL );
504
58
                [[fallthrough]];
505
1.88k
            case RTF_FNIL:
506
1.88k
                aFont.SetFamily( FAMILY_DONTKNOW );
507
1.88k
                break;
508
6.19k
            case RTF_FCHARSET:
509
6.19k
                if (-1 != nTokenValue)
510
6.14k
                {
511
6.14k
                    rtl_TextEncoding nrtl_TextEncoding = rtl_getTextEncodingFromWindowsCharset(
512
6.14k
                        static_cast<sal_uInt8>(nTokenValue));
513
6.14k
                    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
6.14k
                    if (nrtl_TextEncoding == RTL_TEXTENCODING_SYMBOL)
517
371
                        nrtl_TextEncoding = RTL_TEXTENCODING_DONTKNOW;
518
6.14k
                    SetEncoding(nrtl_TextEncoding);
519
6.14k
                }
520
6.19k
                break;
521
4.43k
            case RTF_FPRQ:
522
4.43k
                switch( nTokenValue )
523
4.43k
                {
524
449
                    case 1:
525
449
                        aFont.SetPitch( PITCH_FIXED );
526
449
                        break;
527
3.44k
                    case 2:
528
3.44k
                        aFont.SetPitch( PITCH_VARIABLE );
529
3.44k
                        break;
530
4.43k
                }
531
4.43k
                break;
532
8.18k
            case RTF_F:
533
8.18k
                bCheckNewFont = true;
534
8.18k
                nInsFontNo = nFontNo;
535
8.18k
                nFontNo = static_cast<short>(nTokenValue);
536
8.18k
                break;
537
571
            case RTF_FALT:
538
571
                bIsAltFntNm = true;
539
571
                break;
540
15.1k
            case RTF_TEXTTOKEN:
541
15.1k
                DelCharAtEnd( aToken, ';' );
542
15.1k
                if ( !aToken.isEmpty() )
543
12.1k
                {
544
12.1k
                    if( bIsAltFntNm )
545
603
                        sAltNm = aToken;
546
11.5k
                    else
547
11.5k
                        sFntNm = aToken;
548
12.1k
                }
549
15.1k
                break;
550
71.8k
        }
551
552
71.8k
        if( bCheckNewFont && 1 >= _nOpenBrackets && !sFntNm.isEmpty() )  // one font is ready
553
6.97k
        {
554
            // All data from the font is available, so off to the table
555
6.97k
            if (!sAltNm.isEmpty())
556
550
                sFntNm += ";" + sAltNm;
557
558
6.97k
            aFont.SetFamilyName( sFntNm );
559
6.97k
            m_FontTable.insert(std::make_pair(nInsFontNo, aFont));
560
6.97k
            aFont = vcl::Font();
561
6.97k
            aFont.SetCharSet( nSystemChar );
562
6.97k
            sAltNm.clear();
563
6.97k
            sFntNm.clear();
564
6.97k
        }
565
71.8k
    }
566
934
    SkipToken();        // the closing brace is evaluated "above"
567
568
    // set the default font in the Document
569
934
    if( bNewDoc && IsParserWorking() )
570
0
        SetDefault( RTF_DEFF, nDfltFont );
571
934
}
572
573
void SvxRTFParser::ClearColorTbl()
574
0
{
575
0
    maColorTable.clear();
576
0
}
577
578
void SvxRTFParser::ClearAttrStack()
579
5.56k
{
580
5.56k
    aAttrStack.clear();
581
5.56k
}
582
583
void SvxRTFParser::DelCharAtEnd( OUStringBuffer& rStr, const sal_Unicode cDel )
584
27.7k
{
585
27.7k
    rStr.strip(' ');
586
27.7k
    if( !rStr.isEmpty() && cDel == rStr[ rStr.getLength()-1 ])
587
12.0k
        rStr.setLength( rStr.getLength()-1 );
588
27.7k
}
589
590
591
const vcl::Font& SvxRTFParser::GetFont( sal_uInt16 nId )
592
58.0k
{
593
58.0k
    SvxRTFFontTbl::const_iterator it = m_FontTable.find( nId );
594
58.0k
    if (it != m_FontTable.end())
595
20.1k
    {
596
20.1k
        return it->second;
597
20.1k
    }
598
37.8k
    const SvxFontItem& rDfltFont =
599
37.8k
        pAttrPool->GetUserOrPoolDefaultItem(aPlainMap[SID_ATTR_CHAR_FONT]);
600
37.8k
    pDfltFont->SetFamilyName( rDfltFont.GetStyleName() );
601
37.8k
    pDfltFont->SetFamily( rDfltFont.GetFamily() );
602
37.8k
    return *pDfltFont;
603
58.0k
}
604
605
std::unique_ptr<SvxRTFItemStackType> SvxRTFItemStackType::createSvxRTFItemStackType(
606
    SfxItemPool& rPool, const WhichRangesContainer& pWhichRange, const EditPosition& rEditPosition)
607
7.38k
{
608
7.38k
    struct MakeUniqueEnabler : public SvxRTFItemStackType
609
7.38k
    {
610
7.38k
        MakeUniqueEnabler(SfxItemPool& rPool, const WhichRangesContainer& pWhichRange, const EditPosition& rEditPosition)
611
7.38k
            : SvxRTFItemStackType(rPool, pWhichRange, rEditPosition)
612
7.38k
        {
613
7.38k
        }
614
7.38k
    };
615
7.38k
    return std::make_unique<MakeUniqueEnabler>(rPool, pWhichRange, rEditPosition);
616
7.38k
}
617
618
SvxRTFItemStackType* SvxRTFParser::GetAttrSet_()
619
77.4k
{
620
77.4k
    SvxRTFItemStackType* pCurrent = aAttrStack.empty() ? nullptr : aAttrStack.back().get();
621
77.4k
    std::unique_ptr<SvxRTFItemStackType> xNew;
622
77.4k
    if( pCurrent )
623
70.0k
        xNew = std::make_unique<SvxRTFItemStackType>(*pCurrent, *mxInsertPosition, false/*bCopyAttr*/);
624
7.38k
    else
625
7.38k
        xNew = SvxRTFItemStackType::createSvxRTFItemStackType(*pAttrPool, aWhichMap, *mxInsertPosition);
626
77.4k
    xNew->SetRTFDefaults( GetRTFDefaults() );
627
628
77.4k
    aAttrStack.push_back( std::move(xNew) );
629
630
77.4k
    if (aAttrStack.size() > 96 && comphelper::IsFuzzing())
631
27
        throw std::range_error("ecStackOverflow");
632
633
77.4k
    bNewGroup = false;
634
77.4k
    return aAttrStack.back().get();
635
77.4k
}
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
115k
{
683
115k
    if( aAttrStack.empty() )
684
3.73k
        return;
685
686
111k
    std::unique_ptr<SvxRTFItemStackType> pOld = std::move(aAttrStack.back());
687
111k
    aAttrStack.pop_back();
688
111k
    SvxRTFItemStackType *pCurrent = aAttrStack.empty() ? nullptr : aAttrStack.back().get();
689
690
111k
    do {        // middle check loop
691
111k
        sal_Int32 nOldSttNdIdx = pOld->mxStartNodeIdx->GetIdx();
692
111k
        if (pOld->maChildList.empty() &&
693
91.9k
            ((!pOld->aAttrSet.Count() && !pOld->nStyleNo ) ||
694
91.9k
            (nOldSttNdIdx == mxInsertPosition->GetNodeIdx() &&
695
44.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
107k
        if( pCurrent && pOld->aAttrSet.Count() )
700
70.0k
        {
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
70.0k
            std::vector<sal_uInt16> aDeleteWhichIDs;
706
707
372k
            for (SfxItemIter aIter(pOld->aAttrSet); !aIter.IsAtEnd(); aIter.NextItem())
708
302k
            {
709
302k
                const SfxPoolItem* pGet(nullptr);
710
302k
                if (SfxItemState::SET == pCurrent->aAttrSet.GetItemState(aIter.GetCurWhich(), false, &pGet)
711
132k
                    && *aIter.GetCurItem() == *pGet)
712
110k
                    aDeleteWhichIDs.push_back(aIter.GetCurWhich());
713
302k
            }
714
715
70.0k
            for (auto nDelWhich : aDeleteWhichIDs)
716
110k
                pOld->aAttrSet.ClearItem(nDelWhich);
717
718
70.0k
            if (!pOld->aAttrSet.Count() && pOld->maChildList.empty() &&
719
13.7k
                !pOld->nStyleNo )
720
11.9k
                break;
721
70.0k
        }
722
723
        // Set all attributes which have been defined from start until here
724
95.6k
        bool bCrsrBack = !mxInsertPosition->GetCntIdx();
725
95.6k
        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
95.6k
        if( pOld->mxStartNodeIdx->GetIdx() < mxInsertPosition->GetNodeIdx() ||
735
60.0k
            ( pOld->mxStartNodeIdx->GetIdx() == mxInsertPosition->GetNodeIdx() &&
736
60.0k
              pOld->nSttCnt <= mxInsertPosition->GetCntIdx() ) )
737
95.6k
        {
738
95.6k
            if( !bCrsrBack )
739
70.9k
            {
740
                // all pard attributes are only valid until the previous
741
                // paragraph !!
742
70.9k
                if( nOldSttNdIdx == mxInsertPosition->GetNodeIdx() )
743
40.6k
                {
744
40.6k
                }
745
30.2k
                else
746
30.2k
                {
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
30.2k
                    auto xNew = std::make_unique<SvxRTFItemStackType>(*pOld, *mxInsertPosition, true);
752
30.2k
                    xNew->aAttrSet.SetParent( pOld->aAttrSet.GetParent() );
753
754
                    // Delete all paragraph attributes from xNew
755
30.2k
                    for (const auto& pair : aPardMap.data)
756
515k
                        if (sal_uInt16 wid = pair.second)
757
393k
                            xNew->aAttrSet.ClearItem(wid);
758
30.2k
                    xNew->SetRTFDefaults( GetRTFDefaults() );
759
760
                    // Were there any?
761
30.2k
                    if( xNew->aAttrSet.Count() == pOld->aAttrSet.Count() )
762
7.07k
                    {
763
7.07k
                        xNew.reset();
764
7.07k
                    }
765
23.2k
                    else
766
23.2k
                    {
767
23.2k
                        xNew->nStyleNo = 0;
768
769
                        // Now span the real area of xNew from old
770
23.2k
                        SetEndPrevPara( pOld->mxEndNodeIdx, pOld->nEndCnt );
771
23.2k
                        xNew->nSttCnt = 0;
772
773
23.2k
                        if( IsChkStyleAttr() )
774
0
                        {
775
0
                            ClearStyleAttr_( *pOld );
776
0
                            ClearStyleAttr_( *xNew );   //#i10381#, methinks.
777
0
                        }
778
779
23.2k
                        if( pCurrent )
780
18.7k
                        {
781
18.7k
                            pCurrent->Add(std::move(pOld));
782
18.7k
                            pCurrent->Add(std::move(xNew));
783
18.7k
                        }
784
4.51k
                        else
785
4.51k
                        {
786
                            // Last off the stack, thus cache it until the next text was
787
                            // read. (Span no attributes!)
788
789
4.51k
                            m_AttrSetList.push_back(std::move(pOld));
790
4.51k
                            m_AttrSetList.push_back(std::move(xNew));
791
4.51k
                        }
792
23.2k
                        break;
793
23.2k
                    }
794
30.2k
                }
795
70.9k
            }
796
797
72.4k
            pOld->mxEndNodeIdx = mxInsertPosition->MakeNodeIdx();
798
72.4k
            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
72.4k
            if (IsChkStyleAttr() && !pCurrent)
811
0
                ClearStyleAttr_( *pOld );
812
813
72.4k
            if( pCurrent )
814
39.4k
            {
815
39.4k
                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
39.4k
                if (bCrsrBack && 50 < pCurrent->maChildList.size())
819
151
                {
820
                    // at the beginning of a paragraph? Move back one position
821
151
                    MovePos();
822
151
                    bCrsrBack = false;
823
824
                    // Open a new Group.
825
151
                    auto xNew(std::make_unique<SvxRTFItemStackType>(*pCurrent, *mxInsertPosition, true));
826
151
                    xNew->SetRTFDefaults( GetRTFDefaults() );
827
828
                    // Set all until here valid Attributes
829
151
                    AttrGroupEnd();
830
151
                    pCurrent = aAttrStack.empty() ? nullptr : aAttrStack.back().get();  // can be changed after AttrGroupEnd!
831
151
                    xNew->aAttrSet.SetParent( pCurrent ? &pCurrent->aAttrSet : nullptr );
832
151
                    aAttrStack.push_back( std::move(xNew) );
833
151
                }
834
39.4k
            }
835
33.0k
            else
836
                // Last off the stack, thus cache it until the next text was
837
                // read. (Span no attributes!)
838
33.0k
                m_AttrSetList.push_back(std::move(pOld));
839
72.4k
        }
840
841
72.4k
        if( bCrsrBack )
842
            // at the beginning of a paragraph? Move back one position
843
24.5k
            MovePos();
844
845
72.4k
    } while( false );
846
847
111k
    bNewGroup = false;
848
111k
}
849
850
void SvxRTFParser::SetAllAttrOfStk()        // end all Attr. and set it into doc
851
642
{
852
    // repeat until all attributes will be taken from stack
853
6.40k
    while( !aAttrStack.empty() )
854
5.76k
        AttrGroupEnd();
855
856
1.33k
    for (size_t n = m_AttrSetList.size(); n; )
857
688
    {
858
688
        auto const& pStkSet = m_AttrSetList[--n];
859
688
        SetAttrSet( *pStkSet );
860
688
        pStkSet->DropChildList();
861
688
        m_AttrSetList.pop_back();
862
688
    }
863
642
}
864
865
// sets all the attributes that are different from the current
866
void SvxRTFParser::SetAttrSet( SvxRTFItemStackType &rSet )
867
87.9k
{
868
    // Was DefTab never read? then set to default
869
87.9k
    if( !bIsSetDfltTab )
870
87.9k
        SetDefault( RTF_DEFTAB, 720 );
871
872
87.9k
    if (!rSet.maChildList.empty())
873
17.8k
        rSet.Compress( *this );
874
87.9k
    if( rSet.aAttrSet.Count() || rSet.nStyleNo )
875
81.6k
        SetAttrInDoc( rSet );
876
877
    // then process all the children
878
134k
    for (size_t n = 0; n < rSet.maChildList.size(); ++n)
879
46.7k
        SetAttrSet( *(rSet.maChildList[ n ]) );
880
87.9k
}
881
882
// Has no text been inserted yet? (SttPos from the top Stack entry!)
883
bool SvxRTFParser::IsAttrSttPos()
884
24.3k
{
885
24.3k
    SvxRTFItemStackType* pCurrent = aAttrStack.empty() ? nullptr : aAttrStack.back().get();
886
24.3k
    return !pCurrent || (pCurrent->mxStartNodeIdx->GetIdx() == mxInsertPosition->GetNodeIdx() &&
887
20.1k
        pCurrent->nSttCnt == mxInsertPosition->GetCntIdx());
888
24.3k
}
889
890
891
void SvxRTFParser::SetAttrInDoc( SvxRTFItemStackType & )
892
0
{
893
0
}
894
895
void SvxRTFParser::BuildWhichTable()
896
9.83k
{
897
9.83k
    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
9.83k
    static constexpr sal_uInt16 WIDS1[] {
903
9.83k
             SID_ATTR_PARA_LINESPACE,
904
9.83k
             SID_ATTR_PARA_ADJUST,
905
9.83k
             SID_ATTR_TABSTOP,
906
9.83k
             SID_ATTR_PARA_HYPHENZONE,
907
9.83k
             SID_ATTR_LRSPACE,
908
9.83k
             SID_ATTR_ULSPACE,
909
9.83k
             SID_ATTR_BRUSH,
910
9.83k
             SID_ATTR_BORDER_OUTER,
911
9.83k
             SID_ATTR_BORDER_SHADOW,
912
9.83k
             SID_ATTR_PARA_OUTLLEVEL,
913
9.83k
             SID_ATTR_PARA_SPLIT,
914
9.83k
             SID_ATTR_PARA_KEEP,
915
9.83k
             SID_PARA_VERTALIGN,
916
9.83k
             SID_ATTR_PARA_SCRIPTSPACE,
917
9.83k
             SID_ATTR_PARA_HANGPUNCTUATION,
918
9.83k
             SID_ATTR_PARA_FORBIDDEN_RULES,
919
9.83k
             SID_ATTR_FRAMEDIRECTION,
920
9.83k
         };
921
9.83k
    for (sal_uInt16 nWid : WIDS1)
922
167k
    {
923
167k
        sal_uInt16 nTrueWid = pAttrPool->GetTrueWhichIDFromSlotID(nWid, false);
924
167k
        aPardMap.data[nWid] = nTrueWid;
925
167k
        if (nTrueWid == 0)
926
68.8k
            continue;
927
98.3k
        aWhichMap = aWhichMap.MergeRange(nTrueWid, nTrueWid);
928
98.3k
    }
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
9.83k
    static constexpr sal_uInt16 WIDS[] {
934
9.83k
             SID_ATTR_CHAR_CASEMAP,        SID_ATTR_BRUSH_CHAR,        SID_ATTR_CHAR_COLOR,
935
9.83k
             SID_ATTR_CHAR_CONTOUR,        SID_ATTR_CHAR_STRIKEOUT,    SID_ATTR_CHAR_ESCAPEMENT,
936
9.83k
             SID_ATTR_CHAR_FONT,           SID_ATTR_CHAR_FONTHEIGHT,   SID_ATTR_CHAR_KERNING,
937
9.83k
             SID_ATTR_CHAR_LANGUAGE,       SID_ATTR_CHAR_POSTURE,      SID_ATTR_CHAR_SHADOWED,
938
9.83k
             SID_ATTR_CHAR_UNDERLINE,      SID_ATTR_CHAR_OVERLINE,     SID_ATTR_CHAR_WEIGHT,
939
9.83k
             SID_ATTR_CHAR_WORDLINEMODE,   SID_ATTR_CHAR_AUTOKERN,     SID_ATTR_CHAR_CJK_FONT,
940
9.83k
             SID_ATTR_CHAR_CJK_FONTHEIGHT, sal_uInt16(SID_ATTR_CHAR_CJK_LANGUAGE), SID_ATTR_CHAR_CJK_POSTURE,
941
9.83k
             SID_ATTR_CHAR_CJK_WEIGHT,     SID_ATTR_CHAR_CTL_FONT,     SID_ATTR_CHAR_CTL_FONTHEIGHT,
942
9.83k
             SID_ATTR_CHAR_CTL_LANGUAGE,   SID_ATTR_CHAR_CTL_POSTURE,  SID_ATTR_CHAR_CTL_WEIGHT,
943
9.83k
             SID_ATTR_CHAR_EMPHASISMARK,   SID_ATTR_CHAR_TWO_LINES,    SID_ATTR_CHAR_SCALEWIDTH,
944
9.83k
             SID_ATTR_CHAR_ROTATED,        SID_ATTR_CHAR_RELIEF,       SID_ATTR_CHAR_HIDDEN,
945
9.83k
         };
946
9.83k
    for (sal_uInt16 nWid : WIDS)
947
324k
    {
948
324k
        sal_uInt16 nTrueWid = pAttrPool->GetTrueWhichIDFromSlotID(nWid, false);
949
324k
        aPlainMap.data[nWid] = nTrueWid;
950
324k
        if (nTrueWid == 0)
951
39.3k
            continue;
952
285k
        aWhichMap = aWhichMap.MergeRange(nTrueWid, nTrueWid);
953
285k
    }
954
9.83k
}
955
956
const SfxItemSet& SvxRTFParser::GetRTFDefaults()
957
212k
{
958
212k
    if( !pRTFDefaults )
959
6.43k
    {
960
6.43k
        pRTFDefaults.reset(new SfxItemSet(*pAttrPool, aWhichMap));
961
6.43k
        if (const sal_uInt16 nId = aPardMap[SID_ATTR_PARA_SCRIPTSPACE])
962
6.43k
        {
963
6.43k
            SvxScriptSpaceItem aItem( false, nId );
964
6.43k
            if( bNewDoc )
965
0
                pAttrPool->SetUserDefaultItem( aItem );
966
6.43k
            else
967
6.43k
                pRTFDefaults->Put( aItem );
968
6.43k
        }
969
6.43k
    }
970
212k
    return *pRTFDefaults;
971
212k
}
972
973
974
SvxRTFStyleType::SvxRTFStyleType(SfxItemPool& rPool, const WhichRangesContainer& pWhichRange)
975
13.2k
    : aAttrSet(rPool, pWhichRange)
976
13.2k
    , nBasedOn(0)
977
13.2k
    , nOutlineNo(sal_uInt8(-1))         // not set
978
13.2k
{
979
13.2k
}
980
981
SvxRTFItemStackType::SvxRTFItemStackType(
982
        SfxItemPool& rPool, const WhichRangesContainer& pWhichRange,
983
        const EditPosition& rPos )
984
7.38k
    : aAttrSet( rPool, pWhichRange )
985
7.38k
    , mxStartNodeIdx(rPos.MakeNodeIdx())
986
7.38k
    , mxEndNodeIdx(mxStartNodeIdx)
987
7.38k
    , nSttCnt(rPos.GetCntIdx())
988
7.38k
    , nEndCnt(nSttCnt)
989
7.38k
    , nStyleNo(0)
990
7.38k
{
991
7.38k
}
992
993
SvxRTFItemStackType::SvxRTFItemStackType(
994
        const SvxRTFItemStackType& rCpy,
995
        const EditPosition& rPos,
996
        bool const bCopyAttr )
997
177k
    : aAttrSet( *rCpy.aAttrSet.GetPool(), rCpy.aAttrSet.GetRanges() )
998
177k
    , mxStartNodeIdx(rPos.MakeNodeIdx())
999
177k
    , mxEndNodeIdx(mxStartNodeIdx)
1000
177k
    , nSttCnt(rPos.GetCntIdx())
1001
177k
    , nEndCnt(nSttCnt)
1002
177k
    , nStyleNo(rCpy.nStyleNo)
1003
177k
{
1004
177k
    aAttrSet.SetParent( &rCpy.aAttrSet );
1005
177k
    if( bCopyAttr )
1006
107k
        aAttrSet.Put( rCpy.aAttrSet );
1007
177k
}
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
688
{
1021
688
    if (maChildList.empty())
1022
350
        return;
1023
1024
338
    std::vector<SvxRTFItemStackType*> bfs;
1025
338
    std::queue<SvxRTFItemStackType*> aQueue;
1026
338
    aQueue.push(this);
1027
1028
29.4k
    while (!aQueue.empty())
1029
29.1k
    {
1030
29.1k
        auto* front = aQueue.front();
1031
29.1k
        aQueue.pop();
1032
29.1k
        if (!front->maChildList.empty())
1033
7.01k
        {
1034
7.01k
            for (const auto& a : front->maChildList)
1035
28.7k
                aQueue.push(a.get());
1036
7.01k
            bfs.push_back(front);
1037
7.01k
        }
1038
29.1k
    }
1039
1040
7.34k
    for (auto it = bfs.rbegin(); it != bfs.rend(); ++it)
1041
7.01k
    {
1042
7.01k
        SvxRTFItemStackType* pNode = *it;
1043
7.01k
        pNode->maChildList.clear();
1044
7.01k
    }
1045
338
}
1046
1047
SvxRTFItemStackType::~SvxRTFItemStackType()
1048
184k
{
1049
184k
}
1050
1051
void SvxRTFItemStackType::Add(std::unique_ptr<SvxRTFItemStackType> pIns)
1052
76.8k
{
1053
76.8k
    maChildList.push_back(std::move(pIns));
1054
76.8k
}
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
42.6k
{
1065
42.6k
    ENSURE_OR_RETURN_VOID(!maChildList.empty(), "Compress: ChildList empty");
1066
1067
42.6k
    SvxRTFItemStackType* pTmp = maChildList[0].get();
1068
1069
42.6k
    if( !pTmp->aAttrSet.Count() ||
1070
31.8k
        mxStartNodeIdx->GetIdx() != pTmp->mxStartNodeIdx->GetIdx() ||
1071
31.2k
        nSttCnt != pTmp->nSttCnt )
1072
13.5k
        return;
1073
1074
29.1k
    EditNodeIdx aLastNd = *pTmp->mxEndNodeIdx;
1075
29.1k
    sal_Int32 nLastCnt = pTmp->nEndCnt;
1076
1077
29.1k
    SfxItemSet aMrgSet( pTmp->aAttrSet );
1078
55.6k
    for (size_t n = 1; n < maChildList.size(); ++n)
1079
46.5k
    {
1080
46.5k
        pTmp = maChildList[n].get();
1081
46.5k
        if (!pTmp->maChildList.empty())
1082
17.1k
            pTmp->Compress( rParser );
1083
1084
46.5k
        if( !pTmp->nSttCnt
1085
46.5k
            ? (aLastNd.GetIdx() != pTmp->mxStartNodeIdx->GetIdx() - 1 ||
1086
22.2k
               !rParser.IsEndPara( &aLastNd, nLastCnt ) )
1087
46.5k
            : ( pTmp->nSttCnt != nLastCnt ||
1088
4.76k
                aLastNd.GetIdx() != pTmp->mxStartNodeIdx->GetIdx() ))
1089
19.7k
        {
1090
63.4k
            while (++n < maChildList.size())
1091
43.6k
            {
1092
43.6k
                pTmp = maChildList[n].get();
1093
43.6k
                if (!pTmp->maChildList.empty())
1094
7.59k
                    pTmp->Compress( rParser );
1095
43.6k
            }
1096
19.7k
            return;
1097
19.7k
        }
1098
1099
26.7k
        if( n )
1100
26.7k
        {
1101
            // Search for all which are set over the whole area
1102
            // ITEM: SfxItemIter and removing SfxPoolItems:
1103
26.7k
            std::vector<sal_uInt16> aDeleteWhichIDs;
1104
1105
118k
            for (SfxItemIter aIter(aMrgSet); !aIter.IsAtEnd(); aIter.NextItem())
1106
91.5k
            {
1107
91.5k
                const SfxPoolItem* pGet(nullptr);
1108
91.5k
                if (SfxItemState::SET != pTmp->aAttrSet.GetItemState(aIter.GetCurWhich(), false, &pGet)
1109
90.3k
                    || *aIter.GetCurItem() != *pGet)
1110
1.81k
                    aDeleteWhichIDs.push_back(aIter.GetCurWhich());
1111
91.5k
            }
1112
1113
26.7k
            for (auto nDelWhich : aDeleteWhichIDs)
1114
1.81k
                aMrgSet.ClearItem(nDelWhich);
1115
1116
26.7k
            if( !aMrgSet.Count() )
1117
235
                return;
1118
26.7k
        }
1119
1120
26.5k
        aLastNd = *pTmp->mxEndNodeIdx;
1121
26.5k
        nLastCnt = pTmp->nEndCnt;
1122
26.5k
    }
1123
1124
9.10k
    if( mxEndNodeIdx->GetIdx() != aLastNd.GetIdx() || nEndCnt != nLastCnt )
1125
6.15k
        return;
1126
1127
    // It can be merged
1128
2.94k
    aAttrSet.Put( aMrgSet );
1129
1130
2.94k
    size_t n = 0, nChildLen = maChildList.size();
1131
11.2k
    while (n < nChildLen)
1132
8.25k
    {
1133
8.25k
        pTmp = maChildList[n].get();
1134
8.25k
        pTmp->aAttrSet.Differentiate( aMrgSet );
1135
1136
8.25k
        if (pTmp->maChildList.empty() && !pTmp->aAttrSet.Count() && !pTmp->nStyleNo)
1137
5.04k
        {
1138
5.04k
            maChildList.erase( maChildList.begin() + n );
1139
5.04k
            --nChildLen;
1140
5.04k
            continue;
1141
5.04k
        }
1142
3.21k
        ++n;
1143
3.21k
    }
1144
2.94k
}
1145
void SvxRTFItemStackType::SetRTFDefaults( const SfxItemSet& rDefaults )
1146
184k
{
1147
184k
    if( rDefaults.Count() )
1148
184k
    {
1149
184k
        SfxItemIter aIter( rDefaults );
1150
184k
        const SfxPoolItem* pItem = aIter.GetCurItem();
1151
184k
        do {
1152
184k
            sal_uInt16 nWhich = pItem->Which();
1153
184k
            if( SfxItemState::SET != aAttrSet.GetItemState( nWhich, false ))
1154
107k
                aAttrSet.Put(*pItem);
1155
1156
184k
            pItem = aIter.NextItem();
1157
184k
        } while(pItem);
1158
184k
    }
1159
184k
}
1160
1161
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */