blob: 20b2dc4f8771502c8afa94812d80d2fdd89fb66a [file] [log] [blame]
Adedeji Adebisi684ec912021-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"
kuiyingdfb0cd92023-03-14 11:43:23 +080016
Adedeji Adebisi684ec912021-07-22 18:07:52 +000017#include "main.hpp"
18
19int Munch(const std::string& sv, int* idx, std::string* out)
20{
21 if (*idx >= static_cast<int>(sv.size()))
22 return -INVALID;
23 while (::isspace(sv[*idx]))
24 {
25 (*idx)++;
26 }
27 int ret = 0;
28 *out = "";
29 int quote_state = 0; // 0: not seen, 1: seen opening quotation, 2: ended
30 while (*idx < static_cast<int>(sv.size()))
31 {
32 const char ch = sv[*idx];
33 if (::isspace(ch) && quote_state != 1)
34 {
35 break;
36 }
37 (*idx)++;
38 if (ch == '<')
39 {
40 if (*idx < static_cast<int>(sv.size()) && sv[*idx] == '!')
41 {
42 ret = 10; // Comment
43 }
44 else if (*idx < static_cast<int>(sv.size()) && sv[*idx] == '/')
45 {
46 ret = 22; // Closing tag
47 (*idx)++; // Skip the '/'
48 }
49 else
50 {
51 ret = 1; // <
52 }
53 }
54 else if (ch == '>')
55 {
56 if (ret == 1)
57 {
58 ret = 12;
59 } // < >
60 else if (ret == 22)
61 {}
62 else
63 ret = 2; // >
64 if (out->size() == 0)
65 {
66 (*idx)++;
67 }
68 break; // Do not consume
69 }
70 else if (ch == '\"')
71 {
72 ret = 3; //
73 switch (quote_state)
74 {
75 case 0:
76 {
77 quote_state = 1;
78 continue;
79 }
80 case 1:
81 {
82 quote_state = 2;
83 break;
84 }
85 }
86 }
87 else if (ch == '/' && *idx < static_cast<int>(sv.size()) &&
88 sv[*idx] == '>')
89 {
90 ret = 22; // Closing tag
91 (*idx)++;
92 break;
93 }
94 else
95 {
96 out->push_back(ch);
97 }
98 }
99 return ret;
100}
101
102XMLNode* ParseXML(const std::string& sv)
103{
104 int verbose = 0;
105 char* v = getenv("VERBOSE");
106 if (v)
107 {
108 verbose = std::atoi(v);
109 }
110 int idx = 0;
111 std::string out;
112 int res;
113 std::vector<std::string> tags;
114 std::vector<XMLNode*> nodestack;
115 XMLNode* root = nullptr;
116 if (verbose > 0)
117 {
118 printf("%s\n", sv.c_str());
119 }
120 while ((res = Munch(sv, &idx, &out)) != -INVALID)
121 {
122 if (res == 1 || res == 12)
123 {
124 XMLNode* newnode = new XMLNode(out);
125 if (tags.empty())
126 {
127 root = newnode;
128 }
129 else
130 {
131 nodestack.back()->AddChild(newnode);
132 }
133 tags.push_back(out);
134 nodestack.push_back(newnode);
135 }
136
137 // Add name (has to be before pop_back)
138 if (out.find("name=") == 0)
139 {
140 nodestack.back()->SetName(out.substr(5));
141 }
142
143 if (res == 22 && tags.size() > 0)
144 {
145 tags.pop_back();
146 nodestack.pop_back();
147 }
148 if (verbose >= 2)
149 {
150 printf("Munch %d %s, tags:", res, out.c_str());
151 for (const std::string& x : tags)
152 {
153 printf(" %s", x.c_str());
154 }
155 printf("\n");
156 }
157 }
158 return root;
159}
160
161void DeleteTree(XMLNode* x)
162{
163 for (XMLNode* ch : x->children)
164 {
165 DeleteTree(ch);
166 }
167 delete x;
168}
169
170std::vector<std::string> XMLNode::GetChildNodeNames()
171{
172 std::vector<std::string> ret;
173 for (XMLNode* n : children)
174 {
175 if (n->tag == "node")
176 {
177 ret.push_back(n->fields["name"]);
178 }
179 }
180 return ret;
181}
182
183std::vector<std::string> XMLNode::GetInterfaceNames()
184{
185 std::vector<std::string> ret;
186 for (XMLNode* n : children)
187 {
188 if (n->tag == "interface")
189 {
190 ret.push_back(n->fields["name"]);
191 }
192 }
193 return ret;
Patrick Williamsc3aa2a82023-05-10 07:51:38 -0500194}