blob: 2e4b1a3472b8b22de5679f753c496cffa770ee97 [file] [log] [blame]
Adedeji Adebisi12c5f112021-07-22 18:07:52 +00001// Copyright 2021 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "xmlparse.hpp"
16#include "main.hpp"
17
18int Munch(const std::string& sv, int* idx, std::string* out)
19{
20 if (*idx >= static_cast<int>(sv.size()))
21 return -INVALID;
22 while (::isspace(sv[*idx]))
23 {
24 (*idx)++;
25 }
26 int ret = 0;
27 *out = "";
28 int quote_state = 0; // 0: not seen, 1: seen opening quotation, 2: ended
29 while (*idx < static_cast<int>(sv.size()))
30 {
31 const char ch = sv[*idx];
32 if (::isspace(ch) && quote_state != 1)
33 {
34 break;
35 }
36 (*idx)++;
37 if (ch == '<')
38 {
39 if (*idx < static_cast<int>(sv.size()) && sv[*idx] == '!')
40 {
41 ret = 10; // Comment
42 }
43 else if (*idx < static_cast<int>(sv.size()) && sv[*idx] == '/')
44 {
45 ret = 22; // Closing tag
46 (*idx)++; // Skip the '/'
47 }
48 else
49 {
50 ret = 1; // <
51 }
52 }
53 else if (ch == '>')
54 {
55 if (ret == 1)
56 {
57 ret = 12;
58 } // < >
59 else if (ret == 22)
60 {}
61 else
62 ret = 2; // >
63 if (out->size() == 0)
64 {
65 (*idx)++;
66 }
67 break; // Do not consume
68 }
69 else if (ch == '\"')
70 {
71 ret = 3; //
72 switch (quote_state)
73 {
74 case 0:
75 {
76 quote_state = 1;
77 continue;
78 }
79 case 1:
80 {
81 quote_state = 2;
82 break;
83 }
84 }
85 }
86 else if (ch == '/' && *idx < static_cast<int>(sv.size()) &&
87 sv[*idx] == '>')
88 {
89 ret = 22; // Closing tag
90 (*idx)++;
91 break;
92 }
93 else
94 {
95 out->push_back(ch);
96 }
97 }
98 return ret;
99}
100
101XMLNode* ParseXML(const std::string& sv)
102{
103 int verbose = 0;
104 char* v = getenv("VERBOSE");
105 if (v)
106 {
107 verbose = std::atoi(v);
108 }
109 int idx = 0;
110 std::string out;
111 int res;
112 std::vector<std::string> tags;
113 std::vector<XMLNode*> nodestack;
114 XMLNode* root = nullptr;
115 if (verbose > 0)
116 {
117 printf("%s\n", sv.c_str());
118 }
119 while ((res = Munch(sv, &idx, &out)) != -INVALID)
120 {
121 if (res == 1 || res == 12)
122 {
123 XMLNode* newnode = new XMLNode(out);
124 if (tags.empty())
125 {
126 root = newnode;
127 }
128 else
129 {
130 nodestack.back()->AddChild(newnode);
131 }
132 tags.push_back(out);
133 nodestack.push_back(newnode);
134 }
135
136 // Add name (has to be before pop_back)
137 if (out.find("name=") == 0)
138 {
139 nodestack.back()->SetName(out.substr(5));
140 }
141
142 if (res == 22 && tags.size() > 0)
143 {
144 tags.pop_back();
145 nodestack.pop_back();
146 }
147 if (verbose >= 2)
148 {
149 printf("Munch %d %s, tags:", res, out.c_str());
150 for (const std::string& x : tags)
151 {
152 printf(" %s", x.c_str());
153 }
154 printf("\n");
155 }
156 }
157 return root;
158}
159
160void DeleteTree(XMLNode* x)
161{
162 for (XMLNode* ch : x->children)
163 {
164 DeleteTree(ch);
165 }
166 delete x;
167}
168
169std::vector<std::string> XMLNode::GetChildNodeNames()
170{
171 std::vector<std::string> ret;
172 for (XMLNode* n : children)
173 {
174 if (n->tag == "node")
175 {
176 ret.push_back(n->fields["name"]);
177 }
178 }
179 return ret;
180}
181
182std::vector<std::string> XMLNode::GetInterfaceNames()
183{
184 std::vector<std::string> ret;
185 for (XMLNode* n : children)
186 {
187 if (n->tag == "interface")
188 {
189 ret.push_back(n->fields["name"]);
190 }
191 }
192 return ret;
193}