Botan 3.13.0
Crypto and TLS for C&
parsing.cpp
Go to the documentation of this file.
1/*
2* Various string utils and parsing functions
3* (C) 1999-2007,2013,2014,2015,2018 Jack Lloyd
4* (C) 2015 Simon Warta (Kullo GmbH)
5* (C) 2017 René Korthaus, Rohde & Schwarz Cybersecurity
6*
7* Botan is released under the Simplified BSD License (see license.txt)
8*/
9
10#include <botan/internal/parsing.h>
11
12#include <botan/exceptn.h>
13#include <botan/internal/fmt.h>
14#include <botan/internal/loadstor.h>
15#include <concepts>
16#include <limits>
17#include <sstream>
18
19namespace Botan {
20
21namespace {
22
23std::optional<size_t> digit_from_ascii(char c) {
24 if(c >= '0' && c <= '9') {
25 return c - '0';
26 } else {
27 return {};
28 }
29}
30
31template <std::unsigned_integral T>
32std::optional<T> parse_decimal_integer(std::string_view input, bool require_canonical) {
33 if(input.empty() || input.size() > (std::numeric_limits<T>::digits10 + 1)) {
34 return {};
35 }
36
37 // The canonical encoding of zero is "0"; no other value starts with a zero
38 if(require_canonical && input.size() > 1 && input.front() == '0') {
39 return {};
40 }
41
42 T accum = 0;
43
44 for(const char c : input) {
45 if(const auto digit = digit_from_ascii(c)) {
46 if(accum > (std::numeric_limits<T>::max() - static_cast<T>(*digit)) / 10) {
47 return {};
48 }
49 accum = accum * 10 + static_cast<T>(*digit);
50 } else {
51 return {};
52 }
53 }
54
55 return accum;
56}
57
58} // namespace
59
60std::optional<uint16_t> parse_u16(std::string_view input, bool require_canonical) {
61 return parse_decimal_integer<uint16_t>(input, require_canonical);
62}
63
64std::optional<uint32_t> parse_u32(std::string_view input, bool require_canonical) {
65 return parse_decimal_integer<uint32_t>(input, require_canonical);
66}
67
68std::optional<uint64_t> parse_u64(std::string_view input, bool require_canonical) {
69 return parse_decimal_integer<uint64_t>(input, require_canonical);
70}
71
72std::optional<size_t> parse_sz(std::string_view input, bool require_canonical) {
73 return parse_decimal_integer<size_t>(input, require_canonical);
74}
75
76uint32_t to_u32bit(std::string_view input) {
77 if(const auto parsed = parse_u32(input)) {
78 return *parsed;
79 } else {
80 throw Invalid_Argument(fmt("Failed to parse input '{}' as a 32-bit integer", input));
81 }
82}
83
84/*
85* Parse a SCAN-style algorithm name
86*/
87std::vector<std::string> parse_algorithm_name(std::string_view scan_name) {
88 if(scan_name.find('(') == std::string::npos && scan_name.find(')') == std::string::npos) {
89 return {std::string(scan_name)};
90 }
91
92 std::string name(scan_name);
93 std::string substring;
94 std::vector<std::string> elems;
95 size_t level = 0;
96
97 elems.push_back(name.substr(0, name.find('(')));
98 name = name.substr(name.find('('));
99
100 for(auto i = name.begin(); i != name.end(); ++i) {
101 const char c = *i;
102
103 if(c == '(') {
104 ++level;
105 }
106 if(c == ')') {
107 if(level == 1 && i == name.end() - 1) {
108 if(elems.size() == 1) {
109 elems.push_back(substring.substr(1));
110 } else {
111 elems.push_back(substring);
112 }
113 return elems;
114 }
115
116 if(level == 0 || (level == 1 && i != name.end() - 1)) {
117 throw Invalid_Algorithm_Name(scan_name);
118 }
119 --level;
120 }
121
122 if(c == ',' && level == 1) {
123 if(elems.size() == 1) {
124 elems.push_back(substring.substr(1));
125 } else {
126 elems.push_back(substring);
127 }
128 substring.clear();
129 } else {
130 substring += c;
131 }
132 }
133
134 if(!substring.empty()) {
135 throw Invalid_Algorithm_Name(scan_name);
136 }
137
138 return elems;
139}
140
141std::vector<std::string> split_on(std::string_view str, char delim) {
142 std::vector<std::string> elems;
143 if(str.empty()) {
144 return elems;
145 }
146
147 std::string substr;
148 for(const char c : str) {
149 if(c == delim) {
150 if(!substr.empty()) {
151 elems.push_back(substr);
152 }
153 substr.clear();
154 } else {
155 substr += c;
156 }
157 }
158
159 if(substr.empty()) {
160 throw Invalid_Argument(fmt("Unable to split string '{}", str));
161 }
162 elems.push_back(substr);
163
164 return elems;
165}
166
167/*
168* Join a string
169*/
170std::string string_join(const std::vector<std::string>& strs, char delim) {
171 std::ostringstream out;
172
173 for(size_t i = 0; i != strs.size(); ++i) {
174 if(i != 0) {
175 out << delim;
176 }
177 out << strs[i];
178 }
179
180 return out.str();
181}
182
183std::string tolower_string(std::string_view str) {
184 // Locale-independent ASCII fold; the only callers (DNS name canonicalization
185 // for SAN/name-constraints) work on ASCII strings per RFC 1035.
186 std::string lower(str);
187 for(char& c : lower) {
188 if(c >= 'A' && c <= 'Z') {
189 c = static_cast<char>(c + ('a' - 'A'));
190 }
191 }
192 return lower;
193}
194
195} // namespace Botan
std::optional< uint64_t > parse_u64(std::string_view input, bool require_canonical)
Definition parsing.cpp:68
std::string fmt(std::string_view format, const T &... args)
Definition fmt.h:53
std::string tolower_string(std::string_view str)
Definition parsing.cpp:183
std::vector< std::string > split_on(std::string_view str, char delim)
Definition parsing.cpp:141
std::optional< size_t > parse_sz(std::string_view input, bool require_canonical)
Definition parsing.cpp:72
std::optional< uint32_t > parse_u32(std::string_view input, bool require_canonical)
Definition parsing.cpp:64
std::vector< std::string > parse_algorithm_name(std::string_view scan_name)
Definition parsing.cpp:87
std::string string_join(const std::vector< std::string > &strs, char delim)
Definition parsing.cpp:170
std::optional< uint16_t > parse_u16(std::string_view input, bool require_canonical)
Definition parsing.cpp:60
uint32_t to_u32bit(std::string_view input)
Definition parsing.cpp:76