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