Botan 3.13.0
Crypto and TLS for C&
scan_name.cpp
Go to the documentation of this file.
1/*
2* SCAN Name Abstraction
3* (C) 2008-2009,2015 Jack Lloyd
4*
5* Botan is released under the Simplified BSD License (see license.txt)
6*/
7
8#include <botan/internal/scan_name.h>
9
10#include <botan/assert.h>
11#include <botan/exceptn.h>
12#include <botan/internal/parsing.h>
13
14namespace Botan {
15
16namespace {
17
18std::string make_arg(const std::vector<std::pair<size_t, std::string>>& name, size_t start) {
19 std::string output = name[start].second;
20 size_t level = name[start].first;
21
22 size_t paren_depth = 0;
23
24 for(size_t i = start + 1; i != name.size(); ++i) {
25 if(name[i].first <= name[start].first) {
26 break;
27 }
28
29 if(name[i].first > level) {
30 for(size_t j = level; j < name[i].first; j++) {
31 output += "(";
32 ++paren_depth;
33 }
34 output += name[i].second;
35 } else if(name[i].first < level) {
36 for(size_t j = name[i].first; j < level; j++) {
37 output += ")";
38 BOTAN_ASSERT_NOMSG(paren_depth != 0);
39 --paren_depth;
40 }
41 output += "," + name[i].second;
42 } else {
43 if(output[output.size() - 1] != '(') {
44 output += ",";
45 }
46 output += name[i].second;
47 }
48
49 level = name[i].first;
50 }
51
52 for(size_t i = 0; i != paren_depth; ++i) {
53 output += ")";
54 }
55
56 return output;
57}
58
59} // namespace
60
61SCAN_Name::SCAN_Name(std::string_view algo_spec) : m_orig_algo_spec(algo_spec) {
62 if(algo_spec.empty()) {
63 throw Invalid_Argument("Expected algorithm name, got empty string");
64 }
65
66 // Fast path for a bare name with no arguments or modes (eg "SHA-256"),
67 // which is the common case. Equivalent to the general parse below, which
68 // for such input produces a single token and no args/modes.
69 if(algo_spec.find_first_of("(),/") == std::string_view::npos) {
70 m_alg_name = std::string(algo_spec);
71 return;
72 }
73
74 std::vector<std::pair<size_t, std::string>> name;
75 size_t level = 0;
76 std::pair<size_t, std::string> accum = std::make_pair(level, "");
77
78 bool expect_token = true;
79
80 for(const char c : algo_spec) {
81 if(c == '/' || c == ',' || c == '(' || c == ')') {
82 if(c == '(') {
83 ++level;
84 } else if(c == ')') {
85 if(level == 0) {
86 throw Invalid_Algorithm_Name(m_orig_algo_spec);
87 }
88 --level;
89 }
90
91 if(c == '/' && level > 0) {
92 accum.second.push_back(c);
93 expect_token = false;
94 } else {
95 if(expect_token) {
96 throw Invalid_Algorithm_Name(m_orig_algo_spec);
97 }
98 if(!accum.second.empty()) {
99 name.push_back(accum);
100 }
101 accum = std::make_pair(level, "");
102 expect_token = (c != ')');
103 }
104 } else {
105 accum.second.push_back(c);
106 expect_token = false;
107 }
108 }
109
110 if(!accum.second.empty()) {
111 name.push_back(accum);
112 }
113
114 if(level != 0) {
115 throw Invalid_Algorithm_Name(m_orig_algo_spec);
116 }
117
118 if(expect_token) {
119 // A trailing separator with no following token, eg "Foo/" or "Foo,"
120 throw Invalid_Algorithm_Name(m_orig_algo_spec);
121 }
122
123 if(name.empty()) {
124 throw Invalid_Algorithm_Name(m_orig_algo_spec);
125 }
126
127 m_alg_name = name[0].second;
128
129 bool in_modes = false;
130
131 for(size_t i = 1; i != name.size(); ++i) {
132 if(name[i].first == 0) {
133 m_mode_info.push_back(make_arg(name, i));
134 in_modes = true;
135 } else if(name[i].first == 1 && !in_modes) {
136 m_args.push_back(make_arg(name, i));
137 }
138 }
139}
140
141std::string SCAN_Name::arg(size_t i) const {
142 if(i >= arg_count()) {
143 throw Invalid_Argument("SCAN_Name::arg " + std::to_string(i) + " out of range for '" + to_string() + "'");
144 }
145 return m_args[i];
146}
147
148std::string SCAN_Name::arg(size_t i, std::string_view def_value) const {
149 if(i >= arg_count()) {
150 return std::string(def_value);
151 }
152 return m_args[i];
153}
154
155size_t SCAN_Name::arg_as_integer(size_t i, size_t def_value) const {
156 if(i >= arg_count()) {
157 return def_value;
158 }
159 return to_u32bit(m_args[i]);
160}
161
162size_t SCAN_Name::arg_as_integer(size_t i) const {
163 return to_u32bit(arg(i));
164}
165
166} // namespace Botan
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:75
std::string arg(size_t i) const
const std::string & to_string() const
Definition scan_name.h:33
size_t arg_count() const
Definition scan_name.h:43
SCAN_Name(std::string_view algo_spec)
Definition scan_name.cpp:61
size_t arg_as_integer(size_t i, size_t def_value) const
uint32_t to_u32bit(std::string_view input)
Definition parsing.cpp:76