Coverage Report

Created: 2026-11-06 11:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/xmloff/source/text/XMLTextListBlockContext.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 <com/sun/star/beans/XPropertySet.hpp>
21
#include <xmloff/xmlimp.hxx>
22
#include <xmloff/xmlnamespace.hxx>
23
#include <xmloff/xmltoken.hxx>
24
#include "XMLTextListItemContext.hxx"
25
#include "XMLTextListBlockContext.hxx"
26
#include <txtlists.hxx>
27
#include <sal/log.hxx>
28
29
30
using namespace ::com::sun::star;
31
using namespace ::com::sun::star::uno;
32
using namespace ::com::sun::star::beans;
33
using namespace ::xmloff::token;
34
35
36
// OD 2008-05-07 #refactorlists#
37
// add optional parameter <bRestartNumberingAtSubList> and its handling
38
XMLTextListBlockContext::XMLTextListBlockContext(
39
        SvXMLImport& rImport,
40
        XMLTextImportHelper& rTxtImp,
41
        const Reference< xml::sax::XFastAttributeList > & xAttrList,
42
        const bool bRestartNumberingAtSubList )
43
80.4k
:   SvXMLImportContext( rImport )
44
80.4k
,   mrTxtImport( rTxtImp )
45
80.4k
,   mnLevel( 0 )
46
80.4k
,   mbRestartNumbering( false )
47
80.4k
,   mbSetDefaults( false )
48
80.4k
{
49
80.4k
    static constexpr OUString s_PropNameDefaultListId = u"DefaultListId"_ustr;
50
80.4k
    {
51
        // get the parent list block context (if any); this is a bit ugly...
52
80.4k
        XMLTextListBlockContext * pLB(nullptr);
53
80.4k
        XMLTextListItemContext  * pLI(nullptr);
54
80.4k
        XMLNumberedParaContext  * pNP(nullptr);
55
80.4k
        rTxtImp.GetTextListHelper().ListContextTop(pLB, pLI, pNP);
56
80.4k
        mxParentListBlock = pLB;
57
80.4k
    }
58
    // Inherit style name from parent list, as well as the flags whether
59
    // numbering must be restarted and formats have to be created.
60
80.4k
    OUString sParentListStyleName;
61
80.4k
    if( mxParentListBlock.is() )
62
0
    {
63
0
        XMLTextListBlockContext *pParent = mxParentListBlock.get();
64
0
        msListStyleName = pParent->msListStyleName;
65
0
        sParentListStyleName = msListStyleName;
66
0
        mxNumRules = pParent->GetNumRules();
67
0
        mnLevel = pParent->GetLevel() + 1;
68
0
        mbRestartNumbering = pParent->IsRestartNumbering() ||
69
0
                             bRestartNumberingAtSubList;
70
0
        mbSetDefaults = pParent->mbSetDefaults;
71
0
        msListId = pParent->GetListId();
72
0
        msContinueListId = pParent->GetContinueListId();
73
0
    }
74
75
80.4k
    bool bIsContinueNumberingAttributePresent( false );
76
80.4k
    for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
77
3
    {
78
3
        switch( aIter.getToken() )
79
3
        {
80
0
        case XML_ELEMENT(XML, XML_ID):
81
//FIXME: there is no UNO API for lists
82
            // xml:id is also the list ID (#i92221#)
83
0
            if ( mnLevel == 0 ) // root <list> element
84
0
            {
85
0
                msListId = aIter.toString();
86
0
            }
87
0
            break;
88
0
        case XML_ELEMENT(TEXT, XML_CONTINUE_NUMBERING):
89
0
            mbRestartNumbering = !IsXMLToken(aIter, XML_TRUE);
90
0
            bIsContinueNumberingAttributePresent = true;
91
0
            break;
92
0
        case XML_ELEMENT(TEXT, XML_STYLE_NAME):
93
0
            msListStyleName = aIter.toString();
94
0
            break;
95
0
        case XML_ELEMENT(TEXT, XML_CONTINUE_LIST):
96
0
            if ( mnLevel == 0 ) // root <list> element
97
0
            {
98
0
                msContinueListId = aIter.toString();
99
0
            }
100
0
            break;
101
3
        default:
102
3
            XMLOFF_WARN_UNKNOWN("xmloff", aIter);
103
3
        }
104
3
    }
105
106
    // Remember this list block.
107
80.4k
    mrTxtImport.GetTextListHelper().PushListContext( this );
108
80.4k
    try
109
80.4k
    {
110
80.4k
        mxNumRules = XMLTextListsHelper::MakeNumRule(GetImport(), mxNumRules,
111
80.4k
            sParentListStyleName, msListStyleName,
112
80.4k
            mnLevel, &mbRestartNumbering, &mbSetDefaults );
113
80.4k
        if( !mxNumRules.is() )
114
0
            return;
115
116
80.4k
        if ( mnLevel != 0 ) // root <list> element
117
0
            return;
118
119
80.4k
        XMLTextListsHelper& rTextListsHelper( mrTxtImport.GetTextListHelper() );
120
        // Inconsistent behavior regarding lists (#i92811#)
121
80.4k
        OUString sListStyleDefaultListId;
122
80.4k
        {
123
80.4k
            uno::Reference< beans::XPropertySet > xNumRuleProps( mxNumRules, UNO_QUERY );
124
80.4k
            if ( xNumRuleProps.is() )
125
80.4k
            {
126
80.4k
                uno::Reference< beans::XPropertySetInfo > xNumRulePropSetInfo(
127
80.4k
                                            xNumRuleProps->getPropertySetInfo());
128
80.4k
                if (xNumRulePropSetInfo.is() &&
129
80.4k
                    xNumRulePropSetInfo->hasPropertyByName(
130
80.4k
                         s_PropNameDefaultListId))
131
80.4k
                {
132
80.4k
                    xNumRuleProps->getPropertyValue(s_PropNameDefaultListId)
133
80.4k
                        >>= sListStyleDefaultListId;
134
80.4k
                    SAL_WARN_IF( sListStyleDefaultListId.isEmpty(), "xmloff",
135
80.4k
                                "no default list id found at numbering rules instance. Serious defect." );
136
80.4k
                }
137
80.4k
            }
138
80.4k
        }
139
80.4k
        if ( msListId.isEmpty() )  // no text:id property found
140
80.4k
        {
141
80.4k
            sal_Int32 nUPD( 0 );
142
80.4k
            sal_Int32 nBuild( 0 );
143
80.4k
            const bool bBuildIdFound = GetImport().getBuildIds( nUPD, nBuild );
144
80.4k
            if ( rImport.IsTextDocInOOoFileFormat() ||
145
80.4k
                 ( bBuildIdFound && nUPD == 680 ) )
146
0
            {
147
                /* handling former documents written by OpenOffice.org:
148
                   use default list id of numbering rules instance, if existing
149
                   (#i92811#)
150
                */
151
0
                if ( !sListStyleDefaultListId.isEmpty() )
152
0
                {
153
0
                    msListId = sListStyleDefaultListId;
154
0
                    if ( !bIsContinueNumberingAttributePresent &&
155
0
                         !mbRestartNumbering &&
156
0
                         rTextListsHelper.IsListProcessed( msListId ) )
157
0
                    {
158
0
                        mbRestartNumbering = true;
159
0
                    }
160
0
                }
161
0
            }
162
80.4k
            if ( msListId.isEmpty() )
163
80.4k
            {
164
                // generate a new list id for the list
165
80.4k
                msListId = rTextListsHelper.GenerateNewListId();
166
80.4k
            }
167
80.4k
        }
168
169
80.4k
        if ( bIsContinueNumberingAttributePresent && !mbRestartNumbering &&
170
0
             msContinueListId.isEmpty() )
171
0
        {
172
0
            const OUString& Last( rTextListsHelper.GetLastProcessedListId() );
173
0
            if ( rTextListsHelper.GetListStyleOfLastProcessedList() == msListStyleName
174
0
                 && Last != msListId )
175
0
            {
176
0
                msContinueListId = Last;
177
0
            }
178
0
        }
179
180
80.4k
        bool bContinueNumbering = bIsContinueNumberingAttributePresent && !mbRestartNumbering;
181
80.4k
        if (msContinueListId.isEmpty() && bContinueNumbering && GetImport().IsMSO())
182
0
        {
183
            // No "continue list" id, but continue numbering was requested. Connect to the last list of
184
            // the same list style in the Word case, even if there was a different list in the meantime.
185
0
            msContinueListId = rTextListsHelper.GetLastIdOfStyleName(msListStyleName);
186
0
        }
187
188
80.4k
        if ( !msContinueListId.isEmpty() )
189
0
        {
190
0
            if ( !rTextListsHelper.IsListProcessed( msContinueListId ) )
191
0
            {
192
0
                msContinueListId.clear();
193
0
            }
194
0
            else
195
0
            {
196
                // search continue list chain for master list and
197
                // continue the master list.
198
0
                OUString sTmpStr =
199
0
                    rTextListsHelper.GetContinueListIdOfProcessedList( msContinueListId );
200
0
                while ( !sTmpStr.isEmpty() )
201
0
                {
202
0
                    msContinueListId = sTmpStr;
203
204
0
                    sTmpStr =
205
0
                        rTextListsHelper.GetContinueListIdOfProcessedList( msContinueListId );
206
0
                }
207
0
            }
208
0
        }
209
210
80.4k
        if ( !rTextListsHelper.IsListProcessed( msListId ) )
211
80.4k
        {
212
            // Inconsistent behavior regarding lists (#i92811#)
213
80.4k
            rTextListsHelper.KeepListAsProcessed(
214
80.4k
                msListId, msListStyleName, msContinueListId,
215
80.4k
                sListStyleDefaultListId );
216
80.4k
        }
217
80.4k
    }
218
80.4k
    catch (uno::Exception&)
219
80.4k
    {
220
        // pop ourselves if anything goes wrong to avoid use-after-free
221
0
        rTxtImp.GetTextListHelper().PopListContext();
222
0
        throw;
223
0
    }
224
80.4k
}
225
226
XMLTextListBlockContext::~XMLTextListBlockContext()
227
80.4k
{
228
80.4k
}
229
230
void XMLTextListBlockContext::endFastElement(sal_Int32 )
231
80.4k
{
232
    // Numbering has not to be restarted if it has been restarted within
233
    // a child list.
234
80.4k
    XMLTextListBlockContext *pParent = mxParentListBlock.get();
235
80.4k
    if( pParent )
236
0
    {
237
0
        pParent->mbRestartNumbering = mbRestartNumbering;
238
0
    }
239
240
    // Restore current list block.
241
80.4k
    mrTxtImport.GetTextListHelper().PopListContext();
242
243
    // Any paragraph following the list within the same list item must not
244
    // be numbered.
245
80.4k
    mrTxtImport.GetTextListHelper().SetListItem( nullptr );
246
80.4k
}
247
248
css::uno::Reference< css::xml::sax::XFastContextHandler > XMLTextListBlockContext::createFastChildContext(
249
    sal_Int32 nElement,
250
    const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
251
309
{
252
309
    SvXMLImportContext *pContext = nullptr;
253
254
309
    bool bHeader = false;
255
309
    switch( nElement )
256
309
    {
257
0
    case XML_ELEMENT(TEXT, XML_LIST_HEADER):
258
0
        bHeader = true;
259
0
        [[fallthrough]];
260
0
    case XML_ELEMENT(TEXT, XML_LIST_ITEM):
261
0
        pContext = new XMLTextListItemContext( GetImport(), mrTxtImport,
262
0
                                              xAttrList, bHeader );
263
0
        break;
264
309
    default:
265
309
        XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement);
266
309
    }
267
268
309
    return pContext;
269
309
}
270
271
272
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */