Gazebo Msgs

API Reference

11.0.0~pre1
FuelMetadata.hh
Go to the documentation of this file.
1/*
2 * Copyright (C) 2023 Open Source Robotics Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17#ifndef GZ_MSGS_CONVERT_FUELMETADATA_HH_
18#define GZ_MSGS_CONVERT_FUELMETADATA_HH_
19
20#include <gz/msgs/config.hh>
21
22// Message Headers
23#include "gz/msgs/fuel_metadata.pb.h"
24
25// Data Headers
26#include <sstream>
27#include <string>
28#include <tinyxml2.h>
29
31
32namespace gz::msgs {
33// Inline bracket to help doxygen filtering.
34inline namespace GZ_MSGS_VERSION_NAMESPACE {
35
37inline bool ConvertFuelMetadata(const std::string &_modelConfigStr,
38 msgs::FuelMetadata &_meta)
39{
40 gz::msgs::FuelMetadata meta;
41
42 auto trimmed = [](std::string _s) -> std::string {
43 // Left trim
44 _s.erase(_s.begin(), std::find_if(_s.begin(), _s.end(),
45 [](int c) {return !std::isspace(c);}));
46
47 // Right trim
48 _s.erase(std::find_if(_s.rbegin(), _s.rend(),
49 [](int c) {return !std::isspace(c);}).base(), _s.end());
50
51 return _s;
52 };
53
54 // Load the model config into tinyxml
55 tinyxml2::XMLDocument modelConfigDoc;
56 if (modelConfigDoc.Parse(_modelConfigStr.c_str()) !=
57 tinyxml2::XML_SUCCESS)
58 {
59 std::cerr << "Unable to parse model config XML string.\n";
60 return false;
61 }
62
63 // Get the top level <model> or <world> element.
64 tinyxml2::XMLElement *topElement = modelConfigDoc.FirstChildElement(
65 "model");
66 bool isModel = true;
67 if (!topElement)
68 {
69 topElement = modelConfigDoc.FirstChildElement("world");
70 if (!topElement)
71 {
72 std::cerr << "Model config string does not contain a "
73 << "<model> or <world> element\n";
74 return false;
75 }
76 isModel = false;
77 }
78
79 // Read the name, which is a mandatory element.
80 tinyxml2::XMLElement *elem = topElement->FirstChildElement("name");
81 if (!elem || !elem->GetText())
82 {
83 std::cerr << "Model config string does not contain a <name> element\n";
84 return false;
85 }
86 meta.set_name(trimmed(elem->GetText()));
87
88 // Read the version, if present.
89 elem = topElement->FirstChildElement("version");
90 if (elem && elem->GetText())
91 {
92 auto version = std::stoi(trimmed(elem->GetText()));
93 meta.set_version(version);
94 }
95
96 // Read the description, if present.
97 elem = topElement->FirstChildElement("description");
98 if (elem && elem->GetText())
99 meta.set_description(trimmed(elem->GetText()));
100
101 // Read the dependencies, if any.
102 elem = topElement->FirstChildElement("depend");
103 while (elem)
104 {
105 auto modelElem = elem->FirstChildElement("model");
106 if (modelElem)
107 {
108 auto uriElem = modelElem->FirstChildElement("uri");
109 if (uriElem)
110 {
111 auto dependency = meta.add_dependencies();
112 dependency->set_uri(uriElem->GetText());
113 }
114 }
115 elem = elem->NextSiblingElement("depend");
116 }
117
118 // Read the authors, if any.
119 elem = topElement->FirstChildElement("author");
120 while (elem)
121 {
122 gz::msgs::FuelMetadata::Contact *author = meta.add_authors();
123 // Get the author name and email
124 if (elem->FirstChildElement("name") &&
125 elem->FirstChildElement("name")->GetText())
126 {
127 author->set_name(trimmed(elem->FirstChildElement("name")->GetText()));
128 }
129 if (elem->FirstChildElement("email") &&
130 elem->FirstChildElement("email")->GetText())
131 {
132 author->set_email(
133 trimmed(elem->FirstChildElement("email")->GetText()));
134 }
135
136 elem = elem->NextSiblingElement("author");
137 }
138
139 // Get the most recent SDF file
140 elem = topElement->FirstChildElement("sdf");
142 while (elem)
143 {
144 if (elem->GetText() && elem->Attribute("version"))
145 {
146 std::string verStr = elem->Attribute("version");
147 math::SemanticVersion ver(trimmed(verStr));
148 if (ver > maxVer)
149 {
150 gz::msgs::Version *verMsg;
151
152 if (isModel)
153 {
154 meta.mutable_model()->mutable_file_format()->set_name("sdf");
155 verMsg =
156 meta.mutable_model()->mutable_file_format()->mutable_version();
157 meta.mutable_model()->set_file(trimmed(elem->GetText()));
158 }
159 else
160 {
161 meta.mutable_world()->mutable_file_format()->set_name("sdf");
162 verMsg =
163 meta.mutable_world()->mutable_file_format()->mutable_version();
164 meta.mutable_world()->set_file(trimmed(elem->GetText()));
165 }
166
167 verMsg->set_major(ver.Major());
168 verMsg->set_minor(ver.Minor());
169 verMsg->set_patch(ver.Patch());
170 verMsg->set_prerelease(ver.Prerelease());
171 verMsg->set_build(ver.Build());
172 }
173 }
174
175 elem = elem->NextSiblingElement("sdf");
176 }
177 if (meta.model().file().empty() && meta.world().file().empty())
178 {
179 std::cerr << "Model config string does not contain an <sdf> element\n";
180 return false;
181 }
182
183 _meta.CopyFrom(meta);
184 return true;
185}
186
188inline bool ConvertFuelMetadata(const msgs::FuelMetadata &_meta,
189 std::string &_modelConfigStr)
190{
192
193 // Output opening tag.
194 if (_meta.has_model())
195 {
196 if (_meta.model().file_format().name() != "sdf")
197 {
198 std::cerr << "Model _metadata does not contain an SDF file.\n";
199 return false;
200 }
201
202 out << "<?xml version='1.0'?>\n"
203 << " <model>\n"
204 << " <sdf version='"
205 << _meta.model().file_format().version().major()
206 << "." << _meta.model().file_format().version().minor() << "'>"
207 << _meta.model().file() << "</sdf>\n";
208 }
209 else
210 {
211 if (_meta.world().file_format().name() != "sdf")
212 {
213 std::cerr << "World _metadata does not contain an SDF file.\n";
214 return false;
215 }
216
217 out << "<?xml version='1.0'?>\n"
218 << " <world>\n"
219 << " <sdf version='"
220 << _meta.world().file_format().version().major()
221 << "." << _meta.world().file_format().version().minor() << "'>"
222 << _meta.world().file() << "</sdf>\n";
223 }
224
225 out << " <name>" << _meta.name() << "</name>\n"
226 << " <version>" << _meta.version() << "</version>\n"
227 << " <description>" << _meta.description() << "</description>\n";
228
229 // Output author information.
230 for (int i = 0; i < _meta.authors_size(); ++i)
231 {
232 out << " <author>\n"
233 << " <name>" << _meta.authors(i).name() << "</name>\n"
234 << " <email>" << _meta.authors(i).email() << "</email>\n"
235 << " </author>\n";
236 }
237
238 // Output dependency information.
239 for (int i = 0; i < _meta.dependencies_size(); ++i)
240 {
241 out << " <depend>\n"
242 << " <model>\n"
243 << " <uri>" << _meta.dependencies(i).uri() << "</uri>\n"
244 << " </model>\n"
245 << " </depend>\n";
246 }
247
248 // Output closing tag.
249 if (_meta.has_model())
250 out << " </model>\n";
251 else
252 out << " </world>\n";
253
254 _modelConfigStr = out.str();
255 return true;
256}
257} // namespce
258} // namespace gz::msgs
259
260#endif // GZ_MSGS_CONVERT_FUELMETADATA_HH_