resource_locator.cpp
Go to the documentation of this file.
1 
29 #include <fstream>
30 #include <console_bridge/console.h>
31 #include <iostream>
32 #include <boost/serialization/access.hpp>
33 #include <boost/serialization/nvp.hpp>
34 #include <boost/serialization/shared_ptr.hpp>
35 #include <boost/serialization/vector.hpp>
36 #include <boost/algorithm/string/classification.hpp>
37 #include <boost/algorithm/string/split.hpp>
39 
41 #include <tesseract_common/types.h>
42 #include <tesseract_common/utils.h>
43 
44 namespace tesseract_common
45 {
46 bool isRelativePath(const std::string& url)
47 {
48  std::filesystem::path path(url);
49  return (url.find("file:///") != 0 && url.find("package://") != 0 && path.is_relative());
50 }
51 
52 bool ResourceLocator::operator==(const ResourceLocator& /*rhs*/) const { return true; }
53 bool ResourceLocator::operator!=(const ResourceLocator& /*rhs*/) const { return false; }
54 
55 template <class Archive>
56 void ResourceLocator::serialize(Archive& /*ar*/, const unsigned int /*version*/)
57 {
58 }
59 
60 GeneralResourceLocator::GeneralResourceLocator(const std::vector<std::string>& environment_variables)
61 {
62  for (const auto& env_variable : environment_variables)
63  {
64  loadEnvironmentVariable(env_variable);
65  }
66 }
67 
68 GeneralResourceLocator::GeneralResourceLocator(const std::vector<std::filesystem::path>& paths,
69  const std::vector<std::string>& environment_variables)
70 {
71  for (const auto& path : paths)
72  {
73  addPath(path);
74  }
75 
76  for (const auto& env_variable : environment_variables)
77  {
78  loadEnvironmentVariable(env_variable);
79  }
80 }
81 
82 bool GeneralResourceLocator::loadEnvironmentVariable(const std::string& environment_variable)
83 {
84  char* ros_package_paths = std::getenv(environment_variable.c_str());
85  if (ros_package_paths != nullptr)
86  {
87  std::vector<std::string> tokens;
88 #ifndef _WIN32
89  boost::split(tokens, ros_package_paths, boost::is_any_of(":"), boost::token_compress_on);
90 #else
91  boost::split(tokens, ros_package_paths, boost::is_any_of(";"), boost::token_compress_on);
92 #endif
93  for (const auto& token : tokens)
94  processToken(token);
95 
96  return true;
97  }
98  return false;
99 }
100 
101 bool GeneralResourceLocator::addPath(const std::filesystem::path& path)
102 {
103  if (std::filesystem::is_directory(path) && std::filesystem::exists(path))
104  {
105  processToken(path.string());
106  return true;
107  }
108 
109  CONSOLE_BRIDGE_logError("Package Path does not exist: %s", path.string().c_str());
110  return false;
111 }
112 
113 void GeneralResourceLocator::processToken(const std::string& token)
114 {
115  std::filesystem::path d(token);
116  if (std::filesystem::is_directory(d) && std::filesystem::exists(d))
117  {
118  // Check current directory
119  std::filesystem::path check = d;
120  check.append("package.xml");
121  if (std::filesystem::exists(check))
122  {
123  std::string dir_name = d.filename().string();
124  if (package_paths_.find(dir_name) == package_paths_.end())
125  package_paths_[dir_name] = d.string();
126  }
127 
128  // Check all subdirectories
129  std::filesystem::recursive_directory_iterator dir(d), end;
130  while (dir != end)
131  {
132  std::filesystem::path check = dir->path();
133  check.append("package.xml");
134  if (std::filesystem::exists(check))
135  {
136  std::string dir_name = dir->path().filename().string();
137  if (package_paths_.find(dir_name) == package_paths_.end())
138  package_paths_[dir_name] = dir->path().string();
139 
140  dir.disable_recursion_pending(); // don't recurse into this directory.
141  }
142 
143  ++dir;
144  }
145  }
146  else
147  {
148  CONSOLE_BRIDGE_logError("Package Path does not exist: %s", token.c_str());
149  }
150 }
151 
152 std::size_t findSeparator(const std::string& str)
153 {
154  const size_t pos_slash = str.find('/');
155  const size_t pos_backslash = str.find('\\');
156 
157  if (pos_slash != std::string::npos && pos_backslash != std::string::npos)
158  return std::min(pos_slash, pos_backslash);
159 
160  if (pos_slash != std::string::npos)
161  return pos_slash;
162 
163  if (pos_backslash != std::string::npos)
164  return pos_backslash;
165 
166  return std::string::npos;
167 }
168 
169 std::shared_ptr<Resource> GeneralResourceLocator::locateResource(const std::string& url) const
170 {
171  std::string mod_url = url;
172  if (url.find("file:///") == 0)
173  {
174  mod_url.erase(0, strlen("file://"));
175  const size_t pos = findSeparator(mod_url);
176  if (pos == std::string::npos)
177  return nullptr;
178  }
179  else if (url.find("package://") == 0)
180  {
181  mod_url.erase(0, strlen("package://"));
182  const size_t pos = findSeparator(mod_url);
183  if (pos == std::string::npos)
184  return nullptr;
185 
186  std::string package = mod_url.substr(0, pos);
187  mod_url.erase(0, pos);
188 
189  auto find_package = package_paths_.find(package);
190  if (find_package != package_paths_.end())
191  {
192  mod_url = find_package->second + mod_url;
193  }
194  else
195  {
196  CONSOLE_BRIDGE_logError("Failed to find package resource %s for %s", package.c_str(), url.c_str());
197  return nullptr;
198  }
199  }
200 
201  if (!std::filesystem::path(mod_url).is_absolute())
202  {
203  CONSOLE_BRIDGE_logWarn("Resource not handled: %s", mod_url.c_str());
204  return nullptr;
205  }
206 
207  return std::make_shared<SimpleLocatedResource>(url, mod_url, std::make_shared<GeneralResourceLocator>(*this));
208 }
209 
210 bool GeneralResourceLocator::operator==(const GeneralResourceLocator& /*rhs*/) const { return true; }
211 bool GeneralResourceLocator::operator!=(const GeneralResourceLocator& /*rhs*/) const { return false; }
212 
213 template <class Archive>
214 void GeneralResourceLocator::serialize(Archive& ar, const unsigned int /*version*/)
215 {
216  ar& BOOST_SERIALIZATION_BASE_OBJECT_NVP(ResourceLocator);
217 }
218 
219 bool Resource::operator==(const Resource& /*rhs*/) const { return true; }
220 bool Resource::operator!=(const Resource& /*rhs*/) const { return false; }
221 
222 template <class Archive>
223 void Resource::serialize(Archive& ar, const unsigned int /*version*/)
224 {
225  ar& BOOST_SERIALIZATION_BASE_OBJECT_NVP(ResourceLocator);
226 }
227 
228 SimpleLocatedResource::SimpleLocatedResource(std::string url, std::string filename, ResourceLocator::ConstPtr parent)
229  : url_(std::move(url)), filename_(std::move(filename)), parent_(std::move(parent))
230 {
231 }
232 
233 bool SimpleLocatedResource::isFile() const { return true; }
234 
235 std::string SimpleLocatedResource::getUrl() const { return url_; }
236 
237 std::string SimpleLocatedResource::getFilePath() const { return filename_; }
238 
239 std::vector<uint8_t> SimpleLocatedResource::getResourceContents() const
240 {
241  // https://codereview.stackexchange.com/questions/22901/reading-all-bytes-from-a-file
242 
243  std::ifstream ifs(filename_, std::ios::binary | std::ios::ate);
244  if (ifs.fail())
245  {
246  CONSOLE_BRIDGE_logError("Could not read all bytes from file: %s", filename_.c_str());
247  return {};
248  }
249  std::ifstream::pos_type pos = ifs.tellg();
250 
251  std::vector<uint8_t> file_contents(static_cast<size_t>(pos));
252 
253  ifs.seekg(0, std::ios::beg);
254  ifs.read(reinterpret_cast<std::ifstream::char_type*>(&file_contents[0]), pos); // NOLINT
255 
256  return file_contents;
257 }
258 
259 std::shared_ptr<std::istream> SimpleLocatedResource::getResourceContentStream() const
260 {
261  std::shared_ptr<std::ifstream> ifs = std::make_shared<std::ifstream>(filename_, std::ios::binary);
262  if (ifs->fail())
263  {
264  CONSOLE_BRIDGE_logError("Could not get resource: %s", filename_.c_str());
265  return nullptr;
266  }
267  return ifs;
268 }
269 
271 {
272  if (parent_ == nullptr || url.empty())
273  return nullptr;
274 
275  if (isRelativePath(url))
276  {
277  // Find the last occurrences of both separators
278  std::size_t last_slash = url_.find_last_of('/');
279  std::size_t last_backslash = url_.find_last_of('\\');
280  std::size_t last_separator{ 0 };
281  if (last_slash != std::string::npos && last_backslash != std::string::npos)
282  last_separator = std::max(last_slash, last_backslash);
283  else if (last_slash != std::string::npos)
284  last_separator = last_slash;
285  else if (last_backslash != std::string::npos)
286  last_separator = last_backslash;
287  else
288  return nullptr;
289 
290  std::filesystem::path path(url);
291  std::string url_base_path = url_.substr(0, last_separator);
292  std::string new_url =
293  url_base_path + std::string(1, std::filesystem::path::preferred_separator) + path.filename().string();
294  CONSOLE_BRIDGE_logDebug("new_url: %s", new_url.c_str());
295  return parent_->locateResource(new_url);
296  }
297 
298  return parent_->locateResource(url);
299 }
300 
302 {
303  bool equal = true;
304  equal &= Resource::operator==(rhs);
305  equal &= url_ == rhs.url_;
306  equal &= filename_ == rhs.filename_;
308  return equal;
309 }
310 
312 
313 template <class Archive>
314 void SimpleLocatedResource::serialize(Archive& ar, const unsigned int /*version*/)
315 {
316  ar& BOOST_SERIALIZATION_BASE_OBJECT_NVP(Resource);
317  ar& BOOST_SERIALIZATION_NVP(url_);
318  ar& BOOST_SERIALIZATION_NVP(filename_);
319  ar& BOOST_SERIALIZATION_NVP(parent_);
320 }
321 
322 BytesResource::BytesResource(std::string url, std::vector<uint8_t> bytes, ResourceLocator::ConstPtr parent)
323  : url_(std::move(url)), bytes_(std::move(bytes)), parent_(std::move(parent))
324 {
325 }
326 
327 BytesResource::BytesResource(std::string url, const uint8_t* bytes, size_t bytes_len, ResourceLocator::ConstPtr parent)
328  : url_(std::move(url))
329  , bytes_(std::vector<uint8_t>(bytes, bytes + bytes_len)) // NOLINT
330  , parent_(std::move(parent))
331 {
332 }
333 
334 bool BytesResource::isFile() const { return false; }
335 std::string BytesResource::getUrl() const { return url_; }
336 std::string BytesResource::getFilePath() const { return ""; }
337 std::vector<uint8_t> BytesResource::getResourceContents() const { return bytes_; }
338 std::shared_ptr<std::istream> BytesResource::getResourceContentStream() const
339 {
340  std::shared_ptr<std::stringstream> o = std::make_shared<std::stringstream>();
341  o->write((const char*)&bytes_.at(0), static_cast<std::streamsize>(bytes_.size())); // NOLINT
342  o->seekg(0, std::stringstream::beg);
343  return o;
344 }
345 
346 Resource::Ptr BytesResource::locateResource(const std::string& url) const
347 {
348  if (parent_ == nullptr || url.empty())
349  return nullptr;
350 
351  tesseract_common::Resource::Ptr resource = parent_->locateResource(url);
352  if (resource != nullptr)
353  return resource;
354 
355  if (!isRelativePath(url))
356  return nullptr;
357 
358  auto last_slash = url_.find_last_of('/');
359  if (last_slash == std::string::npos)
360  return nullptr;
361 
362  std::filesystem::path path(url);
363  std::string url_base_path = url_.substr(0, last_slash);
364  std::string new_url = url_base_path + "/" + path.filename().string();
365  return parent_->locateResource(new_url);
366 }
367 
369 {
370  bool equal = true;
371  equal &= Resource::operator==(rhs);
372  equal &= url_ == rhs.url_;
373  equal &= bytes_ == rhs.bytes_;
375  return equal;
376 }
377 
378 bool BytesResource::operator!=(const BytesResource& rhs) const { return !operator==(rhs); }
379 
380 template <class Archive>
381 void BytesResource::serialize(Archive& ar, const unsigned int /*version*/)
382 {
383  ar& BOOST_SERIALIZATION_BASE_OBJECT_NVP(Resource);
384  ar& BOOST_SERIALIZATION_NVP(url_);
385  ar& BOOST_SERIALIZATION_NVP(bytes_);
386  ar& BOOST_SERIALIZATION_NVP(parent_);
387 }
388 
389 } // namespace tesseract_common
390 
397 
398 BOOST_CLASS_EXPORT_IMPLEMENT(tesseract_common::GeneralResourceLocator)
399 BOOST_CLASS_EXPORT_IMPLEMENT(tesseract_common::SimpleLocatedResource)
400 BOOST_CLASS_EXPORT_IMPLEMENT(tesseract_common::BytesResource)
tesseract_common::SimpleLocatedResource::operator==
bool operator==(const SimpleLocatedResource &rhs) const
Definition: resource_locator.cpp:301
tesseract_common::Resource::serialize
void serialize(Archive &ar, const unsigned int version)
Definition: resource_locator.cpp:223
tesseract_common
Definition: allowed_collision_matrix.h:19
tesseract_common::isRelativePath
bool isRelativePath(const std::string &url)
Definition: resource_locator.cpp:46
tesseract_common::Resource::operator!=
bool operator!=(const Resource &rhs) const
Definition: resource_locator.cpp:220
types.h
Common Tesseract Types.
tesseract_common::SimpleLocatedResource::url_
std::string url_
Definition: resource_locator.h:239
tesseract_common::SimpleLocatedResource::SimpleLocatedResource
SimpleLocatedResource()=default
This is for boost serialization do not use directly.
tesseract_common::pointersEqual
bool pointersEqual(const std::shared_ptr< T > &p1, const std::shared_ptr< T > &p2)
Checks if 2 pointers point to objects that are ==.
Definition: utils.h:336
TESSERACT_SERIALIZE_ARCHIVES_INSTANTIATE
#define TESSERACT_SERIALIZE_ARCHIVES_INSTANTIATE(Type)
Definition: serialization.h:49
macros.h
Common Tesseract Macros.
tesseract_common::BytesResource::serialize
void serialize(Archive &ar, const unsigned int version)
Definition: resource_locator.cpp:381
tesseract_common::GeneralResourceLocator::loadEnvironmentVariable
bool loadEnvironmentVariable(const std::string &environment_variable)
Load paths from an environment variable.
Definition: resource_locator.cpp:82
TESSERACT_COMMON_IGNORE_WARNINGS_PUSH
#define TESSERACT_COMMON_IGNORE_WARNINGS_PUSH
Definition: macros.h:71
tesseract_common::BytesResource::url_
std::string url_
Definition: resource_locator.h:274
tesseract_common::SimpleLocatedResource
Resource implementation for a local file.
Definition: resource_locator.h:201
tesseract_common::BytesResource::BytesResource
BytesResource()=default
This is for boost serialization do not use directly.
tesseract_common::GeneralResourceLocator::processToken
void processToken(const std::string &token)
Definition: resource_locator.cpp:113
tesseract_common::BytesResource::getFilePath
std::string getFilePath() const override final
Get the file path of the resource. Only valid if isFile() is true.
Definition: resource_locator.cpp:336
utils.h
Common Tesseract Utility Functions.
tesseract_common::BytesResource::getResourceContents
std::vector< uint8_t > getResourceContents() const override final
Get the resource as bytes. This function may block.
Definition: resource_locator.cpp:337
tesseract_common::GeneralResourceLocator::GeneralResourceLocator
GeneralResourceLocator(const std::vector< std::string > &environment_variables={ "TESSERACT_RESOURCE_PATH", "ROS_PACKAGE_PATH" })
Construct a new General Resource Locator object using the TESSERACT_RESOURCE_PATH environment variabl...
Definition: resource_locator.cpp:60
tesseract_common::GeneralResourceLocator::operator!=
bool operator!=(const GeneralResourceLocator &rhs) const
Definition: resource_locator.cpp:211
tesseract_common::ResourceLocator::ConstPtr
std::shared_ptr< const ResourceLocator > ConstPtr
Definition: resource_locator.h:57
tesseract_common::BytesResource::isFile
bool isFile() const override final
Returns true if the located resource is a local file.
Definition: resource_locator.cpp:334
tesseract_common::ResourceLocator::operator!=
bool operator!=(const ResourceLocator &rhs) const
Definition: resource_locator.cpp:53
tesseract_common::ResourceLocator
Abstract class for resource loaders.
Definition: resource_locator.h:53
tesseract_common::SimpleLocatedResource::getResourceContents
std::vector< uint8_t > getResourceContents() const override final
Get the resource as bytes. This function may block.
Definition: resource_locator.cpp:239
tesseract_common::GeneralResourceLocator::serialize
void serialize(Archive &ar, const unsigned int version)
Definition: resource_locator.cpp:214
tesseract_common::Resource
Represents resource data available from a file or url.
Definition: resource_locator.h:147
tesseract_common::ResourceLocator::operator==
bool operator==(const ResourceLocator &rhs) const
Definition: resource_locator.cpp:52
tesseract_common::GeneralResourceLocator::package_paths_
std::unordered_map< std::string, std::string > package_paths_
Definition: resource_locator.h:141
tesseract_common::SimpleLocatedResource::operator!=
bool operator!=(const SimpleLocatedResource &rhs) const
Definition: resource_locator.cpp:311
tesseract_common::BytesResource::getUrl
std::string getUrl() const override final
Get the original URL used to locate the file.
Definition: resource_locator.cpp:335
tesseract_common::SimpleLocatedResource::getFilePath
std::string getFilePath() const override final
Get the file path of the resource. Only valid if isFile() is true.
Definition: resource_locator.cpp:237
tesseract_common::SimpleLocatedResource::serialize
void serialize(Archive &ar, const unsigned int version)
Definition: resource_locator.cpp:314
tesseract_common::BytesResource::bytes_
std::vector< uint8_t > bytes_
Definition: resource_locator.h:275
tesseract_common::BytesResource::operator!=
bool operator!=(const BytesResource &rhs) const
Definition: resource_locator.cpp:378
tesseract_common::SimpleLocatedResource::getResourceContentStream
std::shared_ptr< std::istream > getResourceContentStream() const override final
Get the resource as a std::istream. This function and the returned stream may block.
Definition: resource_locator.cpp:259
tesseract_common::SimpleLocatedResource::parent_
ResourceLocator::ConstPtr parent_
Definition: resource_locator.h:241
tesseract_common::GeneralResourceLocator::locateResource
std::shared_ptr< Resource > locateResource(const std::string &url) const override
Locate a resource based on a URL.
Definition: resource_locator.cpp:169
tesseract_common::Resource::operator==
bool operator==(const Resource &rhs) const
Definition: resource_locator.cpp:219
TESSERACT_COMMON_IGNORE_WARNINGS_POP
#define TESSERACT_COMMON_IGNORE_WARNINGS_POP
Definition: macros.h:72
tesseract_common::BytesResource
Definition: resource_locator.h:249
tesseract_common::GeneralResourceLocator::operator==
bool operator==(const GeneralResourceLocator &rhs) const
Definition: resource_locator.cpp:210
resource_locator.h
Locate and retrieve resource data.
tesseract_common::Resource::Ptr
std::shared_ptr< Resource > Ptr
Definition: resource_locator.h:150
tesseract_common::BytesResource::getResourceContentStream
std::shared_ptr< std::istream > getResourceContentStream() const override final
Get the resource as a std::istream. This function and the returned stream may block.
Definition: resource_locator.cpp:338
serialization.h
Additional Boost serialization wrappers.
tesseract_common::GeneralResourceLocator
A general resource loaders using environment variable.
Definition: resource_locator.h:84
tesseract_common::BytesResource::parent_
ResourceLocator::ConstPtr parent_
Definition: resource_locator.h:276
tesseract_common::ResourceLocator::serialize
void serialize(Archive &ar, const unsigned int version)
Definition: resource_locator.cpp:56
tesseract_common::BytesResource::locateResource
Resource::Ptr locateResource(const std::string &url) const override final
Locate a resource based on a URL.
Definition: resource_locator.cpp:346
tesseract_common::SimpleLocatedResource::isFile
bool isFile() const override final
Returns true if the located resource is a local file.
Definition: resource_locator.cpp:233
tesseract_common::BytesResource::operator==
bool operator==(const BytesResource &rhs) const
Definition: resource_locator.cpp:368
tesseract_common::SimpleLocatedResource::locateResource
Resource::Ptr locateResource(const std::string &url) const override final
Locate a resource based on a URL.
Definition: resource_locator.cpp:270
tesseract_common::SimpleLocatedResource::filename_
std::string filename_
Definition: resource_locator.h:240
tesseract_common::SimpleLocatedResource::getUrl
std::string getUrl() const override final
Get the original URL used to locate the file.
Definition: resource_locator.cpp:235
tesseract_common::findSeparator
std::size_t findSeparator(const std::string &str)
Definition: resource_locator.cpp:152
tesseract_common::GeneralResourceLocator::addPath
bool addPath(const std::filesystem::path &path)
Add path to the resource locator.
Definition: resource_locator.cpp:101


tesseract_common
Author(s): Levi Armstrong
autogenerated on Sun May 18 2025 03:01:40