Coverage Report

Created: 2025-12-31 10:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/starmath/source/mathml/mathmlattr.cxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
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
10
#include <mathmlattr.hxx>
11
12
#include <o3tl/safeint.hxx>
13
#include <o3tl/string_view.hxx>
14
#include <rtl/math.h>
15
16
#include <cstddef>
17
#include <string_view>
18
#include <unordered_map>
19
20
static std::size_t ParseMathMLUnsignedNumber(std::u16string_view rStr, Fraction& rUN)
21
13.6k
{
22
13.6k
    auto nLen = rStr.length();
23
13.6k
    std::size_t nDecimalPoint = std::u16string_view::npos;
24
13.6k
    std::size_t nIdx;
25
13.6k
    sal_Int64 nom = 0;
26
13.6k
    sal_Int64 den = 1;
27
13.6k
    bool validNomDen = true;
28
186k
    for (nIdx = 0; nIdx < nLen; nIdx++)
29
186k
    {
30
186k
        auto cD = rStr[nIdx];
31
186k
        if (cD == u'.')
32
10.4k
        {
33
10.4k
            if (nDecimalPoint != std::u16string_view::npos)
34
266
                return std::u16string_view::npos;
35
10.1k
            nDecimalPoint = nIdx;
36
10.1k
            continue;
37
10.4k
        }
38
176k
        if (cD < u'0' || u'9' < cD)
39
13.3k
            break;
40
162k
        if (validNomDen
41
146k
            && (o3tl::checked_multiply(nom, sal_Int64(10), nom)
42
146k
                || o3tl::checked_add(nom, sal_Int64(cD - u'0'), nom)
43
146k
                || nom >= std::numeric_limits<sal_Int32>::max()
44
144k
                || (nDecimalPoint != std::u16string_view::npos
45
62.2k
                    && o3tl::checked_multiply(den, sal_Int64(10), den))))
46
1.93k
        {
47
1.93k
            validNomDen = false;
48
1.93k
        }
49
162k
    }
50
13.4k
    if (nIdx == 0 || (nIdx == 1 && nDecimalPoint == 0))
51
64
        return std::u16string_view::npos;
52
53
    // If the input "xx.yyy" can be represented with nom = xx*10^n + yyy and den = 10^n in sal_Int64
54
    // (where n is the length of "yyy"), then use that to create an accurate Fraction (and TODO: we
55
    // could even ignore trailing "0" characters in "yyy", for a smaller n and thus a greater chance
56
    // of validNomDen); if not, use the less accurate approach of creating a Fraction from double:
57
13.3k
    if (validNomDen)
58
11.4k
    {
59
11.4k
        rUN = Fraction(nom, den);
60
11.4k
    }
61
1.86k
    else
62
1.86k
    {
63
1.86k
        rUN = Fraction(
64
1.86k
            rtl_math_uStringToDouble(rStr.data(), rStr.data() + nIdx, '.', 0, nullptr, nullptr));
65
1.86k
    }
66
67
13.3k
    return nIdx;
68
13.4k
}
69
70
static std::size_t ParseMathMLNumber(std::u16string_view rStr, Fraction& rN)
71
13.7k
{
72
13.7k
    if (rStr.empty())
73
32
        return std::u16string_view::npos;
74
13.6k
    bool bNegative = (rStr[0] == '-');
75
13.6k
    std::size_t nOffset = bNegative ? 1 : 0;
76
13.6k
    auto nIdx = ParseMathMLUnsignedNumber(rStr.substr(nOffset), rN);
77
13.6k
    if (nIdx == std::u16string_view::npos || !rN.IsValid())
78
794
        return std::u16string_view::npos;
79
12.8k
    if (bNegative)
80
10.7k
        rN *= -1;
81
12.8k
    return nOffset + nIdx;
82
13.6k
}
83
84
bool ParseMathMLAttributeLengthValue(std::u16string_view rStr, MathMLAttributeLengthValue& rV)
85
13.7k
{
86
13.7k
    auto nIdx = ParseMathMLNumber(rStr, rV.aNumber);
87
13.7k
    if (nIdx == std::u16string_view::npos)
88
826
        return false;
89
12.8k
    std::u16string_view sRest = rStr.substr(nIdx);
90
12.8k
    if (sRest.empty())
91
55
    {
92
55
        rV.eUnit = MathMLLengthUnit::None;
93
55
    }
94
12.8k
    if (o3tl::starts_with(sRest, u"em"))
95
2.22k
    {
96
2.22k
        rV.eUnit = MathMLLengthUnit::Em;
97
2.22k
    }
98
12.8k
    if (o3tl::starts_with(sRest, u"ex"))
99
20
    {
100
20
        rV.eUnit = MathMLLengthUnit::Ex;
101
20
    }
102
12.8k
    if (o3tl::starts_with(sRest, u"px"))
103
57
    {
104
57
        rV.eUnit = MathMLLengthUnit::Px;
105
57
    }
106
12.8k
    if (o3tl::starts_with(sRest, u"in"))
107
340
    {
108
340
        rV.eUnit = MathMLLengthUnit::In;
109
340
    }
110
12.8k
    if (o3tl::starts_with(sRest, u"cm"))
111
728
    {
112
728
        rV.eUnit = MathMLLengthUnit::Cm;
113
728
    }
114
12.8k
    if (o3tl::starts_with(sRest, u"mm"))
115
13
    {
116
13
        rV.eUnit = MathMLLengthUnit::Mm;
117
13
    }
118
12.8k
    if (o3tl::starts_with(sRest, u"pt"))
119
103
    {
120
103
        rV.eUnit = MathMLLengthUnit::Pt;
121
103
    }
122
12.8k
    if (o3tl::starts_with(sRest, u"pc"))
123
0
    {
124
0
        rV.eUnit = MathMLLengthUnit::Pc;
125
0
    }
126
12.8k
    if (sRest[0] == u'%')
127
21
    {
128
21
        rV.eUnit = MathMLLengthUnit::Percent;
129
21
    }
130
12.8k
    return true;
131
13.7k
}
132
133
bool GetMathMLMathvariantValue(const OUString& rStr, MathMLMathvariantValue& rV)
134
1.43k
{
135
1.43k
    static const std::unordered_map<OUString, MathMLMathvariantValue> aMap{
136
1.43k
        { "normal", MathMLMathvariantValue::Normal },
137
1.43k
        { "bold", MathMLMathvariantValue::Bold },
138
1.43k
        { "italic", MathMLMathvariantValue::Italic },
139
1.43k
        { "bold-italic", MathMLMathvariantValue::BoldItalic },
140
1.43k
        { "double-struck", MathMLMathvariantValue::DoubleStruck },
141
1.43k
        { "bold-fraktur", MathMLMathvariantValue::BoldFraktur },
142
1.43k
        { "script", MathMLMathvariantValue::Script },
143
1.43k
        { "bold-script", MathMLMathvariantValue::BoldScript },
144
1.43k
        { "fraktur", MathMLMathvariantValue::Fraktur },
145
1.43k
        { "sans-serif", MathMLMathvariantValue::SansSerif },
146
1.43k
        { "bold-sans-serif", MathMLMathvariantValue::BoldSansSerif },
147
1.43k
        { "sans-serif-italic", MathMLMathvariantValue::SansSerifItalic },
148
1.43k
        { "sans-serif-bold-italic", MathMLMathvariantValue::SansSerifBoldItalic },
149
1.43k
        { "monospace", MathMLMathvariantValue::Monospace },
150
1.43k
        { "initial", MathMLMathvariantValue::Initial },
151
1.43k
        { "tailed", MathMLMathvariantValue::Tailed },
152
1.43k
        { "looped", MathMLMathvariantValue::Looped },
153
1.43k
        { "stretched", MathMLMathvariantValue::Stretched }
154
1.43k
    };
155
156
1.43k
    auto it = aMap.find(rStr);
157
1.43k
    if (it != aMap.end())
158
629
    {
159
629
        rV = it->second;
160
629
        return true;
161
629
    }
162
805
    return false;
163
1.43k
}
164
165
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */