Coverage Report

Created: 2026-07-10 11:04

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