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