Branch data Line data Source code
1 : : // Copyright (c) 2019-present The Bitcoin Core developers
2 : : // Distributed under the MIT software license, see the accompanying
3 : : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 : :
5 : : #include <util/string.h>
6 : :
7 : : #include <iterator>
8 : : #include <memory>
9 : : #include <regex>
10 : : #include <stdexcept>
11 : : #include <string>
12 : :
13 : : namespace util {
14 : 10 : void ReplaceAll(std::string& in_out, const std::string& search, const std::string& substitute)
15 : : {
16 [ + + ]: 10 : if (search.empty()) return;
17 [ + - ]: 8 : in_out = std::regex_replace(in_out, std::regex(search), substitute);
18 : : }
19 : :
20 : 50 : LineReader::LineReader(std::span<const std::byte> buffer, size_t max_line_length)
21 : 50 : : start(buffer.begin()), end(buffer.end()), max_line_length(max_line_length), it(buffer.begin()) {}
22 : :
23 : 966 : std::optional<std::string_view> LineReader::ReadLine()
24 : : {
25 [ + + ]: 966 : if (it == end) {
26 : 10 : return std::nullopt;
27 : : }
28 : :
29 : 956 : auto line_start = it;
30 : 956 : size_t count = 0;
31 [ + + ]: 10301 : while (it != end) {
32 : : // Read a character from the incoming buffer and increment the iterator
33 : 10299 : auto c = static_cast<char>(*it);
34 [ + + ]: 10299 : ++it;
35 : 10299 : ++count;
36 : : // If the character we just consumed was \n, the line is terminated.
37 : : // The \n itself does not count against max_line_length.
38 [ + + ]: 10299 : if (c == '\n') {
39 : 950 : const std::string_view untrimmed_line(reinterpret_cast<const char*>(std::to_address(line_start)), count);
40 : 950 : std::string_view line = RemoveSuffixView(untrimmed_line, "\n");
41 : 950 : return RemoveSuffixView(line, "\r");
42 : : }
43 : : // If the character we just consumed gives us a line length greater
44 : : // than max_line_length, and we are not at the end of the line (or buffer) yet,
45 : : // that means the line we are currently reading is too long, and we throw.
46 [ + + ]: 9349 : if (count > max_line_length) {
47 : : // Reset iterator
48 : 4 : it = line_start;
49 [ + - ]: 4 : throw std::runtime_error("max_line_length exceeded by LineReader");
50 : : }
51 : : }
52 : : // End of buffer reached without finding a \n or exceeding max_line_length.
53 : : // Reset the iterator so the rest of the buffer can be read granularly
54 : : // with ReadLength() and return null to indicate a line was not found.
55 : 2 : it = line_start;
56 : 2 : return std::nullopt;
57 : : }
58 : :
59 : : // Ignores max_line_length but won't overflow
60 : 25 : std::string_view LineReader::ReadLength(size_t len)
61 : : {
62 [ + + ]: 25 : if (len == 0) return {};
63 [ + + + - ]: 24 : if (Remaining() < len) throw std::runtime_error("Not enough data in buffer");
64 : 23 : std::string_view out(reinterpret_cast<const char*>(std::to_address(it)), len);
65 : 23 : it += len;
66 : 23 : return out;
67 : : }
68 : :
69 : 61 : size_t LineReader::Remaining() const
70 : : {
71 : 61 : return std::distance(it, end);
72 : : }
73 : :
74 : 892 : size_t LineReader::Consumed() const
75 : : {
76 : 892 : return std::distance(start, it);
77 : : }
78 : : } // namespace util
|