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