diff --git a/mcap_vendor/CMakeLists.txt b/mcap_vendor/CMakeLists.txt index 6de89d2053..d981fdb2a4 100644 --- a/mcap_vendor/CMakeLists.txt +++ b/mcap_vendor/CMakeLists.txt @@ -33,7 +33,6 @@ macro(build_mcap_vendor) include(FetchContent) fetchcontent_declare(mcap URL https://github.com/foxglove/mcap/archive/refs/tags/releases/cpp/v0.8.0.tar.gz - URL_HASH SHA1=b44637791da2c9c1cec61a3ba6994f1ef63a228c # v0.8.0 ) fetchcontent_makeavailable(mcap) diff --git a/rosbag2_storage_mcap/src/message_definition_cache.cpp b/rosbag2_storage_mcap/src/message_definition_cache.cpp index 5cfbebac81..44572a2d48 100644 --- a/rosbag2_storage_mcap/src/message_definition_cache.cpp +++ b/rosbag2_storage_mcap/src/message_definition_cache.cpp @@ -27,6 +27,7 @@ #include #include #include +#include namespace rosbag2_storage_mcap::internal { @@ -119,6 +120,24 @@ static std::string delimiter(const DefinitionIdentifier & definition_identifier) return result; } +static std::vector split_string(const std::string & str, + const std::string & delimiter = "\n") +{ + std::vector strings; + std::string::size_type pos = 0; + std::string::size_type prev = 0; + + while ((pos = str.find(delimiter, prev)) != std::string::npos) { + strings.push_back(str.substr(prev, pos - prev)); + prev = pos + delimiter.size(); + } + + // Get the last substring (or only, if delimiter is not found) + strings.push_back(str.substr(prev)); + + return strings; +} + MessageSpec::MessageSpec(Format format, std::string text, const std::string & package_context) : dependencies(parse_dependencies(format, text, package_context)) , text(std::move(text)) @@ -139,15 +158,34 @@ const MessageSpec & MessageDefinitionCache::load_message_spec( throw std::invalid_argument("Invalid package resource name: " + definition_identifier.package_resource_name); } - std::string package = match[1]; - std::string share_dir = ament_index_cpp::get_package_share_directory(package); - std::ifstream file{share_dir + "/msg/" + match[2].str() + - extension_for_format(definition_identifier.format)}; - if (!file.good()) { + const std::string package = match[1].str(); + const std::string filename = match[2].str() + extension_for_format(definition_identifier.format); + + // Get the package share directory, or throw a PackageNotFoundError + const std::string share_dir = ament_index_cpp::get_package_share_directory(package); + + // Get the rosidl_interfaces index contents for this package + std::string index_contents; + if (!ament_index_cpp::get_resource("rosidl_interfaces", package, index_contents)) { throw DefinitionNotFoundError(definition_identifier.package_resource_name); } - std::string contents{std::istreambuf_iterator(file), {}}; + // Find the first line that ends with the filename we're looking for + const auto lines = split_string(index_contents); + const auto it = std::find_if(lines.begin(), lines.end(), [&filename](const std::string & line) { + std::filesystem::path filePath(line); + return filePath.filename() == filename; + }); + if (it == lines.end()) { + throw DefinitionNotFoundError(definition_identifier.package_resource_name); + } + + // Read the file + const std::string full_path = share_dir + std::filesystem::path::preferred_separator + *it; + std::ifstream file{full_path}; + + const std::string contents{std::istreambuf_iterator(file), {}}; + const MessageSpec & spec = msg_specs_by_definition_identifier_ .emplace(definition_identifier,