Gazebo Msgs

API Reference

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