Coverage Report

Created: 2024-11-21 07:03

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