Coverage Report

Created: 2026-10-14 09:33

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