Coverage Report

Created: 2026-08-14 10:22

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