Coverage Report

Created: 2025-06-13 06:46

/src/Fast-DDS/src/cpp/utils/UnitsParser.cpp
Line
Count
Source (jump to first uncovered line)
1
// Copyright 2024 Proyectos y Sistemas de Mantenimiento SL (eProsima).
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
/*
16
 * UnitsParser.cpp
17
 *
18
 */
19
20
#include <utils/UnitsParser.hpp>
21
22
#include <algorithm>
23
#include <cctype>
24
#include <cstdint>
25
#include <limits>
26
#include <map>
27
#include <regex>
28
#include <set>
29
#include <stdexcept>
30
#include <string>
31
32
namespace eprosima {
33
namespace fastdds {
34
namespace dds {
35
namespace utils {
36
37
void to_uppercase(
38
        std::string& st) noexcept
39
19.2k
{
40
    // These lambda has been taken from the notes in https://en.cppreference.com/w/cpp/string/byte/toupper
41
    // Note how the argument passed is unsigned char to avoid undefined behavior
42
19.2k
    auto my_toupper = [](unsigned char c)
43
7.51M
            {
44
7.51M
                return static_cast<char>(std::toupper(c));
45
7.51M
            };
46
19.2k
    std::transform(st.begin(), st.end(), st.begin(), my_toupper);
47
19.2k
}
48
49
uint32_t parse_value_and_units(
50
        std::string& value,
51
        std::string units)
52
20.4k
{
53
20.4k
    static const std::map<std::string, std::uint32_t> magnitudes = {
54
20.4k
        {"", 1},
55
20.4k
        {"B", 1},
56
20.4k
        {"KB", 1000},
57
20.4k
        {"MB", 1000 * 1000},
58
20.4k
        {"GB", 1000 * 1000 * 1000},
59
20.4k
        {"KIB", 1024},
60
20.4k
        {"MIB", 1024 * 1024},
61
20.4k
        {"GIB", 1024 * 1024 * 1024},
62
20.4k
    };
63
64
20.4k
    uint64_t num = 0;
65
20.4k
    try
66
20.4k
    {
67
20.4k
        num = std::stoull(value);
68
20.4k
    }
69
20.4k
    catch (std::out_of_range&)
70
20.4k
    {
71
1.22k
        throw std::invalid_argument("Failed to parse value from string." \
72
1.22k
                      " The number is too large to be converted to bytes (Max: (2^32)-1 Bytes).");
73
1.22k
    }
74
75
19.2k
    to_uppercase(units);
76
77
19.2k
    uint32_t magnitude = 0;
78
19.2k
    try
79
19.2k
    {
80
19.2k
        magnitude = magnitudes.at(units);
81
19.2k
    }
82
19.2k
    catch (std::out_of_range&)
83
19.2k
    {
84
10.0k
        throw std::invalid_argument(
85
10.0k
                  "The units are not in the expected format. Use: {B, KB, MG, GB, KIB, MIB, GIB}.");
86
10.0k
    }
87
88
    // Check whether the product of number * magnitude overflows
89
9.16k
    if (num > std::numeric_limits<std::uint32_t>::max() / magnitude)
90
3.40k
    {
91
3.40k
        throw std::invalid_argument("The number is too large to be converted to bytes (Max: (2^32)-1 Bytes).");
92
3.40k
    }
93
94
    // The explicit cast to uint32_t is safe since the number has already been checked to fit.
95
    // The product is also safe since the possible overflow has also been checked.
96
5.76k
    const std::uint32_t bytes = static_cast<std::uint32_t>(num) * magnitude;
97
98
5.76k
    return bytes;
99
9.16k
}
100
101
} /* namespace utils */
102
} /* namespace dds */
103
} /* namespace fastdds */
104
} /* namespace eprosima */