Botan 3.6.1
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/exceptn.h>
11#include <botan/internal/parsing.h>
12
13namespace Botan {
14
15namespace {
16
17std::string make_arg(const std::vector<std::pair<size_t, std::string>>& name, size_t start) {
18 std::string output = name[start].second;
19 size_t level = name[start].first;
20
21 size_t paren_depth = 0;
22
23 for(size_t i = start + 1; i != name.size(); ++i) {
24 if(name[i].first <= name[start].first) {
25 break;
26 }
27
28 if(name[i].first > level) {
29 output += "(" + name[i].second;
30 ++paren_depth;
31 } else if(name[i].first < level) {
32 for(size_t j = name[i].first; j < level; j++) {
33 output += ")";
34 --paren_depth;
35 }
36 output += "," + name[i].second;
37 } else {
38 if(output[output.size() - 1] != '(') {
39 output += ",";
40 }
41 output += name[i].second;
42 }
43
44 level = name[i].first;
45 }
46
47 for(size_t i = 0; i != paren_depth; ++i) {
48 output += ")";
49 }
50
51 return output;
52}
53
54} // namespace
55
56SCAN_Name::SCAN_Name(const char* algo_spec) : SCAN_Name(std::string(algo_spec)) {}
57
58SCAN_Name::SCAN_Name(std::string_view algo_spec) : m_orig_algo_spec(algo_spec), m_alg_name(), m_args(), m_mode_info() {
59 if(algo_spec.empty()) {
60 throw Invalid_Argument("Expected algorithm name, got empty string");
61 }
62
63 std::vector<std::pair<size_t, std::string>> name;
64 size_t level = 0;
65 std::pair<size_t, std::string> accum = std::make_pair(level, "");
66
67 const std::string decoding_error = "Bad SCAN name '" + m_orig_algo_spec + "': ";
68
69 for(char c : algo_spec) {
70 if(c == '/' || c == ',' || c == '(' || c == ')') {
71 if(c == '(') {
72 ++level;
73 } else if(c == ')') {
74 if(level == 0) {
75 throw Decoding_Error(decoding_error + "Mismatched parens");
76 }
77 --level;
78 }
79
80 if(c == '/' && level > 0) {
81 accum.second.push_back(c);
82 } else {
83 if(!accum.second.empty()) {
84 name.push_back(accum);
85 }
86 accum = std::make_pair(level, "");
87 }
88 } else {
89 accum.second.push_back(c);
90 }
91 }
92
93 if(!accum.second.empty()) {
94 name.push_back(accum);
95 }
96
97 if(level != 0) {
98 throw Decoding_Error(decoding_error + "Missing close paren");
99 }
100
101 if(name.empty()) {
102 throw Decoding_Error(decoding_error + "Empty name");
103 }
104
105 m_alg_name = name[0].second;
106
107 bool in_modes = false;
108
109 for(size_t i = 1; i != name.size(); ++i) {
110 if(name[i].first == 0) {
111 m_mode_info.push_back(make_arg(name, i));
112 in_modes = true;
113 } else if(name[i].first == 1 && !in_modes) {
114 m_args.push_back(make_arg(name, i));
115 }
116 }
117}
118
119std::string SCAN_Name::arg(size_t i) const {
120 if(i >= arg_count()) {
121 throw Invalid_Argument("SCAN_Name::arg " + std::to_string(i) + " out of range for '" + to_string() + "'");
122 }
123 return m_args[i];
124}
125
126std::string SCAN_Name::arg(size_t i, std::string_view def_value) const {
127 if(i >= arg_count()) {
128 return std::string(def_value);
129 }
130 return m_args[i];
131}
132
133size_t SCAN_Name::arg_as_integer(size_t i, size_t def_value) const {
134 if(i >= arg_count()) {
135 return def_value;
136 }
137 return to_u32bit(m_args[i]);
138}
139
140size_t SCAN_Name::arg_as_integer(size_t i) const {
141 return to_u32bit(arg(i));
142}
143
144} // namespace Botan
SCAN_Name(const char *algo_spec)
Definition scan_name.cpp:56
std::string name
uint32_t to_u32bit(std::string_view str_view)
Definition parsing.cpp:32