00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include <introspection/field.h>
00030 #include <introspection/type.h>
00031 #include <introspection/introspection.h>
00032 #include <introspection/message_expansion.h>
00033
00034 #include <dlfcn.h>
00035
00036 #define BOOST_FILESYSTEM_VERSION 3
00037 #include <boost/filesystem.hpp>
00038
00039 namespace cpp_introspection {
00040
00041 static M_Package g_packages;
00042 static V_Package g_repository;
00043 static M_Message g_messages_by_name;
00044 static M_Message g_messages_by_md5sum;
00045 static M_TypeInfo_Message g_messages_by_typeid;
00046 static V_string g_loaded_libraries;
00047
00048 PackagePtr package(const std::string& pkg)
00049 {
00050 if (!g_packages.count(pkg)) return PackagePtr();
00051 return g_packages[pkg].lock();
00052 }
00053
00054 const V_Package &packages() {
00055 return g_repository;
00056 }
00057
00058 MessagePtr messageByDataType(const std::string& data_type, const std::string& package)
00059 {
00060 if (!package.empty()) return messageByDataType(package + "/" + data_type);
00061 if (data_type == "Header") return g_messages_by_name[ros::message_traits::datatype<std_msgs::Header>()].lock();
00062 if (!g_messages_by_name.count(data_type)) return MessagePtr();
00063 return g_messages_by_name[data_type].lock();
00064 }
00065
00066 MessagePtr messageByMD5Sum(const std::string& md5sum)
00067 {
00068 if (!g_messages_by_md5sum.count(md5sum)) return MessagePtr();
00069 return g_messages_by_md5sum[md5sum].lock();
00070 }
00071
00072 MessagePtr messageByTypeId(const std::type_info &type_info) {
00073 if (!g_messages_by_typeid.count(&type_info)) return MessagePtr();
00074 return g_messages_by_typeid[&type_info].lock();
00075 }
00076
00077 PackagePtr Package::add(const PackagePtr& package)
00078 {
00079 if (g_packages.count(package->getName())) return g_packages[package->getName()].lock();
00080 g_repository.push_back(package);
00081 g_packages[package->getName()] = package;
00082 return package;
00083 }
00084
00085 std::vector<std::string> Package::getMessages() const
00086 {
00087 std::vector<std::string> messages;
00088 for(std::vector<MessagePtr>::const_iterator it = messages_.begin(); it != messages_.end(); ++it)
00089 messages.push_back((*it)->getName());
00090
00091 return messages;
00092 }
00093
00094 MessagePtr Package::message(const std::string& message) const
00095 {
00096 return messageByDataType(std::string(getName()) + "/" + message);
00097 }
00098
00099 MessagePtr Package::add(const MessagePtr& message)
00100 {
00101 if (g_messages_by_name.count(message->getDataType())) return g_messages_by_name[message->getDataType()].lock();
00102 messages_.push_back(message);
00103 g_messages_by_name[message->getDataType()] = message;
00104 g_messages_by_md5sum[message->getMD5Sum()] = message;
00105 g_messages_by_typeid[&(message->getTypeId())] = message;
00106 return message;
00107 }
00108
00109 MessagePtr expand(const MessagePtr& message, const std::string &separator, const std::string &prefix)
00110 {
00111 return MessagePtr(new ExpandedMessage(message, separator, prefix));
00112 }
00113
00114 void ExpandedMessage::expand(const MessagePtr &message, const std::string& prefix) {
00115 for(Message::const_iterator i = message->begin(); i != message->end(); i++) {
00116 FieldPtr field = *i;
00117
00118 for(std::size_t j = 0; j < field->size(); j++) {
00119 std::string field_name = (!prefix.empty() ? prefix + separator_ : "") + field->getName();
00120 if (field->isContainer()) field_name += boost::lexical_cast<std::string>(j);
00121
00122 if (field->isMessage()) {
00123 MessagePtr expanded(field->expand(j));
00124 if (!expanded) {
00125 ROS_WARN("Expansion of %s failed: Could not expand field %s with unknown type %s", getDataType(), field->getName(), field->getDataType());
00126 continue;
00127 }
00128 expand(expanded, field_name);
00129 } else {
00130 FieldPtr expanded(new ExpandedField(*field, field_name, j));
00131 fields_.push_back(expanded);
00132 fields_by_name_[field_name] = expanded;
00133 field_names_.push_back(expanded->getName());
00134 }
00135 }
00136 }
00137 }
00138
00139 V_string Message::getFields(bool expand, const std::string& separator, const std::string& prefix) const
00140 {
00141 V_string fields;
00142 return getFields(fields, expand, separator, prefix);
00143 }
00144
00145 V_string& Message::getFields(V_string& fields, bool expand, const std::string& separator, const std::string& prefix) const
00146 {
00147 for(const_iterator it = begin(); it != end(); ++it) {
00148 FieldPtr field = *it;
00149 std::string base(prefix + field->getName());
00150
00151 for (std::size_t index = 0; index < field->size(); ++index) {
00152 std::string name(base);
00153 if (field->isArray()) name = name + boost::lexical_cast<std::string>(index);
00154
00155 if (expand && field->isMessage()) {
00156 MessagePtr expanded = field->expand(index);
00157 if (!expanded) {
00158 ROS_WARN("Expansion of %s failed: Could not expand field %s with unknown type %s", getDataType(), field->getName(), field->getDataType());
00159 continue;
00160 }
00161 expanded->getFields(fields, expand, separator, name + separator);
00162
00163 } else {
00164 fields.push_back(name);
00165 }
00166 }
00167 }
00168
00169 return fields;
00170 }
00171
00172 V_string Message::getTypes(bool expand) const
00173 {
00174 V_string types;
00175 return getTypes(types, expand);
00176 }
00177
00178 V_string& Message::getTypes(V_string& types, bool expand) const
00179 {
00180 for(const_iterator it = begin(); it != end(); ++it) {
00181 FieldPtr field = *it;
00182
00183 for (std::size_t index = 0; index < field->size(); ++index) {
00184 if (expand && field->isMessage()) {
00185 MessagePtr expanded = field->expand(index);
00186 if (!expanded) {
00187 ROS_WARN("Expansion of %s failed: Could not expand field %s with unknown type %s", getDataType(), field->getName(), field->getDataType());
00188 continue;
00189 }
00190 expanded->getTypes(types, expand);
00191
00192 } else {
00193 types.push_back(field->isArray() ? field->getValueType() : field->getDataType());
00194 }
00195 }
00196 }
00197
00198 return types;
00199 }
00200
00201 std::vector<boost::any> Message::getValues(bool expand) const
00202 {
00203 std::vector<boost::any> values;
00204 return getValues(values, expand);
00205 }
00206
00207 std::vector<boost::any>& Message::getValues(std::vector<boost::any>& values, bool expand) const
00208 {
00209 if (!hasInstance()) return values;
00210
00211 for(const_iterator it = begin(); it != end(); ++it) {
00212 FieldPtr field = *it;
00213
00214 for (std::size_t index = 0; index < field->size(); ++index) {
00215 if (expand && field->isMessage()) {
00216 MessagePtr expanded = field->expand(index);
00217 if (!expanded) {
00218 ROS_WARN("Expansion of %s failed: Could not expand field %s with unknown type %s", getDataType(), field->getName(), field->getDataType());
00219 continue;
00220 }
00221 expanded->getValues(values, expand);
00222
00223 } else {
00224 values.push_back(field->get(index));
00225 }
00226 }
00227 }
00228
00229 return values;
00230 }
00231
00232 MessagePtr Field::expand(std::size_t i) const {
00233 if (!isMessage()) return MessagePtr();
00234 return messageByTypeId(this->getTypeId());
00235 }
00236
00237 PackagePtr loadPackage(const std::string &package_name)
00238 {
00239 PackagePtr p = package(package_name);
00240 if (p) return p;
00241 return load("libintrospection_" + package_name + ".so");
00242 }
00243
00244 using namespace boost::filesystem;
00245 PackagePtr load(const std::string& package_or_library_or_path)
00246 {
00247 path path(package_or_library_or_path);
00248 if (is_directory(path)) {
00249 ROS_DEBUG_STREAM_NAMED(ROS_PACKAGE_NAME, "Searching directory " << path << "...");
00250 for(directory_iterator entry(path); entry != directory_iterator(); ++entry) {
00251 ROS_DEBUG_STREAM_NAMED(ROS_PACKAGE_NAME, " " << *entry << "...");
00252 if (is_regular_file(entry->path())) load(entry->path().string());
00253 }
00254
00255 return PackagePtr();
00256 }
00257
00258 if (path.extension() != ".so") {
00259 loadPackage(package_or_library_or_path);
00260 return PackagePtr();
00261 }
00262 ROS_DEBUG_STREAM_NAMED(ROS_PACKAGE_NAME, "Loading " << path << "...");
00263
00264 if (std::find(g_loaded_libraries.begin(), g_loaded_libraries.end(), path.filename()) != g_loaded_libraries.end()) {
00265 ROS_WARN_STREAM_NAMED(ROS_PACKAGE_NAME, "library " << path << " already loaded");
00266 return PackagePtr();
00267 }
00268
00269 void *library = dlopen(path.string().c_str(), RTLD_NOW | RTLD_GLOBAL);
00270 const char *error = dlerror();
00271 if (error || !library) {
00272 ROS_ERROR("%s", error);
00273 return PackagePtr();
00274 }
00275
00276 typedef PackagePtr (*LoadFunction)();
00277 LoadFunction load_fcn = (LoadFunction) dlsym(library, "cpp_introspection_load_package");
00278 error = dlerror();
00279 if (error || !load_fcn) {
00280 ROS_WARN_NAMED(ROS_PACKAGE_NAME, "%s", error);
00281 dlclose(library);
00282 return PackagePtr();
00283 }
00284 PackagePtr package __attribute__((unused)) = (*load_fcn)();
00285
00286 ROS_INFO_STREAM_NAMED(ROS_PACKAGE_NAME, "Successfully loaded cpp_introspection library " << path);
00287 g_loaded_libraries.push_back(path.filename().string());
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298 return package;
00299 }
00300
00301 }