Coverage Report

Created: 2026-06-30 11:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/configmgr/source/partial.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 <sal/config.h>
21
22
#include <cassert>
23
#include <set>
24
25
#include <com/sun/star/uno/RuntimeException.hpp>
26
#include <rtl/ustring.hxx>
27
#include <sal/types.h>
28
29
#include "data.hxx"
30
#include "partial.hxx"
31
32
namespace configmgr {
33
34
namespace {
35
36
bool parseSegment(
37
    OUString const & path, sal_Int32 * index, OUString * segment)
38
0
{
39
0
    assert(
40
0
        index != nullptr && *index >= 0 && *index <= path.getLength() &&
41
0
        segment != nullptr);
42
0
    if (path[(*index)++] == '/') {
43
0
        OUString name;
44
0
        bool setElement;
45
0
        OUString templateName;
46
0
        *index = Data::parseSegment(
47
0
            path, *index, &name, &setElement, &templateName);
48
0
        if (*index != -1) {
49
0
            *segment = Data::createSegment(templateName, name);
50
0
            return *index == path.getLength();
51
0
        }
52
0
    }
53
0
    throw css::uno::RuntimeException("bad path " + path);
54
0
}
55
56
}
57
58
Partial::Partial(
59
    css::uno::Sequence< OUString > const & includedPaths,
60
    css::uno::Sequence< OUString > const & excludedPaths)
61
0
{
62
    // The Partial::Node tree built up here encodes the following information:
63
    // * Inner node, startInclude: an include starts here that contains excluded
64
    //   sub-trees
65
    // * Inner node, !startInclude: contains in-/excluded sub-trees
66
    // * Leaf node, startInclude: an include starts here
67
    // * Leaf node, !startInclude: an exclude starts here
68
0
    for (auto const& includedPath : includedPaths)
69
0
    {
70
0
        sal_Int32 n = 0;
71
0
        for (Node * p = &root_;;) {
72
0
            OUString seg;
73
0
            bool end = parseSegment(includedPath, &n, &seg);
74
0
            p = !seg.isEmpty() ? &p->children[seg] : p;
75
0
            if (p->startInclude) {
76
0
                break;
77
0
            }
78
0
            if (end) {
79
0
                p->children.clear();
80
0
                p->startInclude = true;
81
0
                break;
82
0
            }
83
0
        }
84
0
    }
85
0
    for (auto const& excludedPath : excludedPaths)
86
0
    {
87
0
        sal_Int32 n = 0;
88
0
        for (Node * p = &root_;;) {
89
0
            OUString seg;
90
0
            bool end = parseSegment(excludedPath, &n, &seg);
91
0
            if (end) {
92
0
                p->children[seg].clear();
93
0
                break;
94
0
            }
95
0
            Node::Children::iterator j(p->children.find(seg));
96
0
            if (j == p->children.end()) {
97
0
                break;
98
0
            }
99
0
            p = &j->second;
100
0
        }
101
0
    }
102
0
}
103
104
0
Partial::~Partial() {}
105
106
0
Partial::Containment Partial::contains(std::vector<OUString> const & path) const {
107
    //TODO: For set elements, the segment names recorded in the node tree need
108
    // not match the corresponding path segments, so this function can fail.
109
110
    // * If path ends at a leaf node or goes past a leaf node:
111
    // ** If that leaf node is startInclude: => CONTAINS_NODE
112
    // ** If that leaf node is !startInclude: => CONTAINS_NOT
113
    // * If path ends at inner node:
114
    // ** If there is some startInclude along its trace: => CONTAINS_NODE
115
    // ** If there is no startInclude along its trace: => CONTAINS_SUBNODES
116
0
    Node const * p = &root_;
117
0
    bool bIncludes = false;
118
0
    for (auto const& elemPath : path)
119
0
    {
120
0
        Node::Children::const_iterator j(p->children.find(elemPath));
121
0
        if (j == p->children.end()) {
122
0
            return p->startInclude ? CONTAINS_NODE : CONTAINS_NOT;
123
0
        }
124
0
        p = &j->second;
125
0
        bIncludes |= p->startInclude;
126
0
    }
127
0
    return p->children.empty() && !p->startInclude
128
0
        ? CONTAINS_NOT
129
0
        : bIncludes ? CONTAINS_NODE : CONTAINS_SUBNODES;
130
0
}
131
132
}
133
134
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */