diff --git a/src/user/user_objects.cc b/src/user/user_objects.cc index 66619b05..df3980a0 100644 --- a/src/user/user_objects.cc +++ b/src/user/user_objects.cc @@ -33,7 +33,6 @@ #include #include "lodepng.h" -#include #include #include #include @@ -45,7 +44,6 @@ #include "user/user_model.h" #include "user/user_resource.h" #include "user/user_util.h" -#include "user/user_vfs.h" namespace { namespace mju = ::mujoco::util; @@ -704,18 +702,14 @@ void mjCBase::NameSpace(const mjCModel* m) { // load resource if found (fallback to OS filesystem) mjResource* mjCBase::LoadResource(std::string filename, const mjVFS* vfs) { - // try reading from provided VFS - mjResource* r = mju_openVfsResource(filename.c_str(), vfs); - - if (!r) { - std::array error; - // not in vfs try a provider or fallback to OS filesystem - r = mju_openResource(filename.c_str(), error.data(), error.size()); - if (!r) { - throw mjCError(nullptr, "%s", error.data()); - } + // try reading from provided VFS or fallback to OS filesystem + std::array error; + mjResource* resource = mju_openResource(filename.c_str(), vfs, + error.data(), error.size()); + if (!resource) { + throw mjCError(nullptr, "%s", error.data()); } - return r; + return resource; } diff --git a/src/user/user_resource.cc b/src/user/user_resource.cc index ebe21238..805a3156 100644 --- a/src/user/user_resource.cc +++ b/src/user/user_resource.cc @@ -18,7 +18,6 @@ #include #include -#include #include #include #include @@ -35,12 +34,16 @@ #endif #include +#include #include "engine/engine_plugin.h" -#include "engine/engine_util_errmem.h" #include "engine/engine_util_misc.h" +#include "user/user_util.h" +#include "user/user_vfs.h" namespace { +using mujoco::user::FileToMemory; + // file buffer used internally for the OS filesystem struct FileSpec { bool is_read; // set to nonzero if buffer was read into @@ -48,11 +51,74 @@ struct FileSpec { time_t mtime; // last modified time }; +// callback for opening a resource, returns zero on failure +int FileOpen(mjResource* resource, char* error, size_t nerror) { + resource->provider = nullptr; + resource->data = new FileSpec; + const char* name = resource->name; + FileSpec* spec = (FileSpec*) resource->data; + spec->is_read = false; + struct stat file_stat; + if (stat(name, &file_stat) == 0) { + memcpy(&spec->mtime, &file_stat.st_mtime, sizeof(time_t)); + } else { + if (error) { + snprintf(error, nerror, "Error opening file '%s': %s", name, + strerror(errno)); + } + return 0; + } + mju_encodeBase64(resource->timestamp, (uint8_t*) &spec->mtime, + sizeof(time_t)); + return 1; +} + +// OS filesystem read callback +int FileRead(mjResource* resource, const void** buffer) { + FileSpec* spec = (FileSpec*) resource->data; + + // only read once from file + if (!spec->is_read) { + spec->buffer = FileToMemory(resource->name); + spec->is_read = true; + } + *buffer = spec->buffer.data(); + return spec->buffer.size(); +} + +// OS filesystem close callback +void FileClose(mjResource* resource) { + FileSpec* spec = (FileSpec*) resource->data; + if (spec) delete spec; +} + +// OS filesystem getdir callback +void FileGetDir(mjResource* resource, const char** dir, int* ndir) { + *dir = resource->name; + *ndir = mjuu_dirnamelen(resource->name); +} + +// OS filesystem modified callback +int FileModified(const mjResource* resource, const char*timestamp) { + if (mju_isValidBase64(timestamp) != sizeof(time_t)) { + return 1; // error (assume modified) + } + + time_t time1, time2; + mju_decodeBase64((uint8_t*) &time1, timestamp); + time2 = ((FileSpec*) resource->data)->mtime; + double diff = difftime(time2, time1); + if (diff < 0) return -1; + if (diff > 0) return 1; + return 0; +} + } // namespace // open the given resource; if the name doesn't have a prefix matching with a // resource provider, then the OS filesystem is used -mjResource* mju_openResource(const char* name, char* error, size_t nerror) { +mjResource* mju_openResource(const char* name, const mjVFS* vfs, + char* error, size_t nerror) { // no error so far if (error) { error[0] = '\0'; @@ -60,7 +126,10 @@ mjResource* mju_openResource(const char* name, char* error, size_t nerror) { mjResource* resource = (mjResource*) mju_malloc(sizeof(mjResource)); if (resource == nullptr) { - mjERROR("could not allocate memory"); + if (error) { + strncpy(error, "could not allocate memory", nerror); + error[nerror - 1] = '\0'; + } return nullptr; } @@ -70,16 +139,30 @@ mjResource* mju_openResource(const char* name, char* error, size_t nerror) { // copy name resource->name = (char*) mju_malloc(sizeof(char) * (strlen(name) + 1)); if (resource->name == nullptr) { + if (error) { + strncpy(error, "could not allocate memory", nerror); + error[nerror - 1] = '\0'; + } mju_closeResource(resource); - mjERROR("could not allocate memory"); return nullptr; } memcpy(resource->name, name, sizeof(char) * (strlen(name) + 1)); + // first priority is to check the VFS + if (vfs != nullptr) { + const mjpResourceProvider* provider = GetVfsResourceProvider(); + resource->data = (void*) vfs; + resource->provider = provider; + if (provider->open(resource)) { + return resource; + } + } + // find provider based off prefix of name const mjpResourceProvider* provider = mjp_getResourceProvider(name); if (provider != nullptr) { resource->provider = provider; + resource->data = nullptr; if (provider->open(resource)) { return resource; } @@ -95,24 +178,11 @@ mjResource* mju_openResource(const char* name, char* error, size_t nerror) { } // lastly fallback to OS filesystem - resource->provider = nullptr; - resource->data = new FileSpec; - FileSpec* spec = (FileSpec*) resource->data; - spec->is_read = false; - struct stat file_stat; - if (stat(name, &file_stat) == 0) { - memcpy(&spec->mtime, &file_stat.st_mtime, sizeof(time_t)); - } else { - if (error) { - snprintf(error, nerror, "Error opening file '%s': %s", name, - strerror(errno)); - } - mju_closeResource(resource); - return nullptr; + if (FileOpen(resource, error, nerror)) { + return resource; } - mju_encodeBase64(resource->timestamp, (uint8_t*) &spec->mtime, - sizeof(time_t)); - return resource; + mju_closeResource(resource); + return nullptr; } @@ -124,14 +194,11 @@ void mju_closeResource(mjResource* resource) { } // use the resource provider close callback - if (resource->provider && resource->provider->close) { - resource->provider->close(resource); + const mjpResourceProvider* provider = resource->provider; + if (provider) { + if (provider->close) provider->close(resource); } else { - // clear OS filesystem if present - FileSpec* spec = (FileSpec*) resource->data; - if (spec) { - delete spec; - } + FileClose(resource); // clear OS filesystem if present } // free resource @@ -149,36 +216,26 @@ int mju_readResource(mjResource* resource, const void** buffer) { } // if provider is NULL, then OS filesystem is used - FileSpec* spec = (FileSpec*) resource->data; - - // only read once from file - if (!spec->is_read) { - spec->buffer = mju_fileToMemory(resource->name); - spec->is_read = true; - } - *buffer = spec->buffer.data(); - return spec->buffer.size(); + return FileRead(resource, buffer); } // get directory path of resource void mju_getResourceDir(mjResource* resource, const char** dir, int* ndir) { - *dir = NULL; + *dir = nullptr; *ndir = 0; - if (resource == NULL) { + if (resource == nullptr) { return; } - // provider is not OS filesystem - if (resource->provider) { - if (resource->provider->getdir) { - resource->provider->getdir(resource, dir, ndir); - } + const mjpResourceProvider* provider = resource->provider; + if (provider) { + if (provider->getdir) provider->getdir(resource, dir, ndir); } else { - *dir = resource->name; - *ndir = mju_dirnamelen(resource->name); + // fallback to OS filesystem + FileGetDir(resource, dir, ndir); } } @@ -197,89 +254,5 @@ int mju_isModifiedResource(const mjResource* resource, const char* timestamp) { } // fallback to OS filesystem - if (mju_isValidBase64(timestamp) != sizeof(time_t)) { - return 1; // error (assume modified) - } - - time_t time1, time2; - mju_decodeBase64((uint8_t*) &time1, timestamp); - time2 = ((FileSpec*) resource->data)->mtime; - double diff = difftime(time2, time1); - if (diff < 0) return -1; - if (diff > 0) return 1; - return 0; -} - - - -// get the length of the dirname portion of a given path -int mju_dirnamelen(const char* path) { - if (!path) { - return 0; - } - - int pos = -1; - for (int i = 0; path[i]; ++i) { - if (path[i] == '/' || path[i] == '\\') { - pos = i; - } - } - - return pos + 1; -} - - - -// read file into memory buffer (allocated here with mju_malloc) -std::vector mju_fileToMemory(const char* filename) { - FILE* fp = fopen(filename, "rb"); - if (!fp) { - return {}; - } - - // find size - if (fseek(fp, 0, SEEK_END) != 0) { - fclose(fp); - mju_warning("Failed to calculate size for '%s'", filename); - return {}; - } - - // ensure file size fits in int - long long_filesize = ftell(fp); // NOLINT(runtime/int) - if (long_filesize > INT_MAX) { - fclose(fp); - mju_warning("File size over 2GB is not supported. File: '%s'", filename); - return {}; - } else if (long_filesize < 0) { - fclose(fp); - mju_warning("Failed to calculate size for '%s'", filename); - return {}; - } - - std::vector buffer(long_filesize); - - // go back to start of file - if (fseek(fp, 0, SEEK_SET) != 0) { - fclose(fp); - mju_warning("Read error while reading '%s'", filename); - return {}; - } - - // allocate and read - std::size_t bytes_read = fread(buffer.data(), 1, buffer.size(), fp); - - // check that read data matches file size - if (bytes_read != buffer.size()) { // SHOULD NOT OCCUR - if (ferror(fp)) { - fclose(fp); - mju_warning("Read error while reading '%s'", filename); - return {}; - } else if (feof(fp)) { - buffer.resize(bytes_read); - } - } - - // close file, return contents - fclose(fp); - return buffer; + return FileModified(resource, timestamp); } diff --git a/src/user/user_resource.h b/src/user/user_resource.h index 3a564091..e64874cb 100644 --- a/src/user/user_resource.h +++ b/src/user/user_resource.h @@ -30,7 +30,8 @@ extern "C" { // open the given resource; if the name doesn't have a prefix matching with a // resource provider, then the OS filesystem is used -MJAPI mjResource* mju_openResource(const char* name, char* error, std::size_t nerror); +MJAPI mjResource* mju_openResource(const char* name, const mjVFS* vfs, + char* error, std::size_t nerror); // close the given resource; no-op if resource is NULL MJAPI void mju_closeResource(mjResource* resource); @@ -47,14 +48,8 @@ MJAPI void mju_getResourceDir(mjResource* resource, const char** dir, int* ndir) // return < 0 if the resource is older than the given timestamp MJAPI int mju_isModifiedResource(const mjResource* resource, const char* timestamp); -// get the length of the dirname portion of a given path -MJAPI int mju_dirnamelen(const char* path); - #ifdef __cplusplus } #endif -// read file into memory buffer (allocated here with mju_malloc) -std::vector mju_fileToMemory(const char* filename); - #endif // MUJOCO_SRC_ENGINE_ENGINE_RESOURCE_H_ diff --git a/src/user/user_util.cc b/src/user/user_util.cc index 6305bca5..92ce36c4 100644 --- a/src/user/user_util.cc +++ b/src/user/user_util.cc @@ -16,8 +16,10 @@ #include #include +#include #include #include +#include #include #include #include @@ -941,6 +943,22 @@ std::string mjuu_extToContentType(std::string_view filename) { } } +// get the length of the dirname portion of a given path +int mjuu_dirnamelen(const char* path) { + if (!path) { + return 0; + } + + int pos = -1; + for (int i = 0; path[i]; ++i) { + if (path[i] == '/' || path[i] == '\\') { + pos = i; + } + } + + return pos + 1; +} + namespace mujoco::user { std::string FilePath::Combine(const std::string& s1, const std::string& s2) { @@ -1012,7 +1030,6 @@ FilePath FilePath::StripExt() const { return FilePathFast(path_.substr(0, n)); } - // is directory absolute path std::string FilePath::AbsPrefix(const std::string& str) { // empty: not absolute @@ -1066,5 +1083,59 @@ std::string FilePath::StrLower() const { return str; } +// read file into memory buffer +std::vector FileToMemory(const char* filename) { + FILE* fp = fopen(filename, "rb"); + if (!fp) { + return {}; + } + + // find size + if (fseek(fp, 0, SEEK_END) != 0) { + fclose(fp); + mju_warning("Failed to calculate size for '%s'", filename); + return {}; + } + + // ensure file size fits in int + long long_filesize = ftell(fp); // NOLINT(runtime/int) + if (long_filesize > INT_MAX) { + fclose(fp); + mju_warning("File size over 2GB is not supported. File: '%s'", filename); + return {}; + } else if (long_filesize < 0) { + fclose(fp); + mju_warning("Failed to calculate size for '%s'", filename); + return {}; + } + + std::vector buffer(long_filesize); + + // go back to start of file + if (fseek(fp, 0, SEEK_SET) != 0) { + fclose(fp); + mju_warning("Read error while reading '%s'", filename); + return {}; + } + + // allocate and read + std::size_t bytes_read = fread(buffer.data(), 1, buffer.size(), fp); + + // check that read data matches file size + if (bytes_read != buffer.size()) { // SHOULD NOT OCCUR + if (ferror(fp)) { + fclose(fp); + mju_warning("Read error while reading '%s'", filename); + return {}; + } else if (feof(fp)) { + buffer.resize(bytes_read); + } + } + + // close file, return contents + fclose(fp); + return buffer; +} + } // namespace mujoco::user diff --git a/src/user/user_util.h b/src/user/user_util.h index 336ee4bb..1bce5010 100644 --- a/src/user/user_util.h +++ b/src/user/user_util.h @@ -16,9 +16,11 @@ #define MUJOCO_SRC_USER_USER_UTIL_H_ #include +#include #include #include #include +#include const double mjEPS = 1E-14; // minimum value in various calculations const double mjMINMASS = 1E-6; // minimum mass allowed @@ -230,6 +232,9 @@ class FilePath { std::string path_; }; +// read file into memory buffer +std::vector FileToMemory(const char* filename); + } // namespace mujoco::user // strip path from filename @@ -258,4 +263,7 @@ std::optional mjuu_parseContentTypeAttrSubtype(std::string_vie // convert filename extension to content type; return empty string if not found std::string mjuu_extToContentType(std::string_view filename); +// get the length of the dirname portion of a given path +int mjuu_dirnamelen(const char* path); + #endif // MUJOCO_SRC_USER_USER_UTIL_H_ diff --git a/src/user/user_vfs.cc b/src/user/user_vfs.cc index 88b6c87d..8bc484a2 100644 --- a/src/user/user_vfs.cc +++ b/src/user/user_vfs.cc @@ -17,19 +17,20 @@ #include #include #include +#include +#include #include #include #include #include -#include "engine/engine_util_errmem.h" #include "engine/engine_util_misc.h" -#include "user/user_resource.h" #include "user/user_util.h" namespace { using mujoco::user::FilePath; +using mujoco::user::FileToMemory; // internal struct for VFS files struct VFSFile { @@ -177,7 +178,7 @@ void Close(mjResource* resource) { // getdir callback for the VFS resource provider void GetDir(mjResource* resource, const char** dir, int* ndir) { *dir = (resource) ? resource->name : nullptr; - *ndir = (resource) ? mju_dirnamelen(resource->name) : 0; + *ndir = (resource) ? mjuu_dirnamelen(resource->name) : 0; } // modified callback for the VFS resource provider @@ -227,7 +228,7 @@ int mj_addFileVFS(mjVFS* vfs, const char* directory, const char* filename) { } // allocate and read - std::vector buffer = mju_fileToMemory(fullname.c_str()); + std::vector buffer = FileToMemory(fullname.c_str()); if (buffer.empty()) { return -1; } @@ -265,44 +266,8 @@ void mj_deleteVFS(mjVFS* vfs) { } } -// open VFS resource -mjResource* mju_openVfsResource(const char* name, const mjVFS* vfs) { - if (vfs == nullptr) { - return nullptr; - } - - // VFS provider - static struct mjpResourceProvider provider = { nullptr, &Open, &Read, &Close, - &GetDir, &Modified, nullptr }; - - // create resource - mjResource* resource = (mjResource*) mju_malloc(sizeof(mjResource)); - if (resource == nullptr) { - mjERROR("could not allocate memory"); - return nullptr; - } - - // clear out resource - memset(resource, 0, sizeof(mjResource)); - - // copy name - std::size_t n = std::strlen(name); - resource->name = (char*) mju_malloc(sizeof(char) * (n + 1)); - if (resource->name == nullptr) { - mju_closeResource(resource); - mjERROR("could not allocate memory"); - return nullptr; - } - std::memcpy(resource->name, name, sizeof(char) * (n + 1)); - resource->data = (void*) vfs; - - // open resource - resource->provider = &provider; - if (provider.open(resource)) { - return resource; - } - - // not found in VFS - mju_closeResource(resource); - return nullptr; +const mjpResourceProvider* GetVfsResourceProvider() { + static mjpResourceProvider provider + = { nullptr, &Open, &Read, &Close, &GetDir, &Modified, nullptr }; + return &provider; } diff --git a/src/user/user_vfs.h b/src/user/user_vfs.h index c133ef66..416de6f7 100644 --- a/src/user/user_vfs.h +++ b/src/user/user_vfs.h @@ -45,11 +45,10 @@ MJAPI int mj_deleteFileVFS(mjVFS* vfs, const char* filename); // delete all files from VFS MJAPI void mj_deleteVFS(mjVFS* vfs); -// open VFS resource -MJAPI mjResource* mju_openVfsResource(const char* name, const mjVFS* vfs); - #ifdef __cplusplus } #endif +const mjpResourceProvider* GetVfsResourceProvider(); + #endif // MUJOCO_SRC_USER_USER_VFS_H_ diff --git a/src/xml/xml.cc b/src/xml/xml.cc index 7ec8243a..9c64ce2d 100644 --- a/src/xml/xml.cc +++ b/src/xml/xml.cc @@ -173,27 +173,23 @@ static void mjIncludeXML(mjXReader& reader, XMLElement* elem, } else { fullname = filename; } - mjResource *resource = mju_openVfsResource(fullname.c_str(), vfs); - if (!resource) { - // load from provider or OS filesystem - std::array error; - resource = mju_openResource(fullname.c_str(), error.data(), error.size()); - if (!resource) { - if (!mjuu_isabspath(filename)) { - fullname = std::string(dir) + filename; - } else { - fullname = filename; - } - // load from provider or OS filesystem - std::array error; - resource = mju_openResource(fullname.c_str(), error.data(), error.size()); - if (!resource) { - throw mjXError(elem, "%s", error.data()); - } + // legacy behavior: try to load in top level directory + std::array error; + mjResource *resource = mju_openResource(fullname.c_str(), vfs, + error.data(), error.size()); + if (resource == nullptr) { + // new behavior: try to load in relative directory + if (!mjuu_isabspath(filename)) { + fullname = std::string(dir) + filename; + resource = mju_openResource(fullname.c_str(), vfs, error.data(), error.size()); } } + if (resource == nullptr) { + throw mjXError(elem, "%s", error.data()); + } + if (!mjuu_isabspath(filename)) { filename = std::string(dir) + filename; } @@ -293,16 +289,12 @@ mjSpec* mjParseXML(const char* filename, const mjVFS* vfs, // get data source const char* xmlstring = nullptr; - mjResource* resource = mju_openVfsResource(filename, vfs); - - if (!resource) { - // load from provider or fallback to OS filesystem - std::array rerror; - resource = mju_openResource(filename, rerror.data(), rerror.size()); - if (!resource) { - std::snprintf(error, error_sz, "mjParseXML: %s", rerror.data()); - return nullptr; - } + std::array rerror; + mjResource* resource = mju_openResource(filename, vfs, + rerror.data(), rerror.size()); + if (resource == nullptr) { + std::snprintf(error, error_sz, "mjParseXML: %s", rerror.data()); + return nullptr; } int buffer_size = mju_readResource(resource, (const void**) &xmlstring); diff --git a/src/xml/xml_api.cc b/src/xml/xml_api.cc index bb4b4aa9..623466ed 100644 --- a/src/xml/xml_api.cc +++ b/src/xml/xml_api.cc @@ -14,6 +14,7 @@ #include "xml/xml_api.h" +#include #include #include #include @@ -186,15 +187,12 @@ int mj_printSchema(const char* filename, char* buffer, int buffer_sz, int flg_ht // load model from binary MJB resource mjModel* mj_loadModel(const char* filename, const mjVFS* vfs) { - mjResource* resource = nullptr; - - // first try vfs, otherwise try a provider or OS filesystem - if (!(resource = mju_openVfsResource(filename, vfs))) { - char error[1024]; - if (!(resource = mju_openResource(filename, error, 1024))) { - mju_warning("%s", error); - return nullptr; - } + std::array error; + mjResource* resource = mju_openResource(filename, vfs, + error.data(), error.size()); + if (resource == nullptr) { + mju_warning("%s", error.data()); + return nullptr; } const void* buffer = NULL; diff --git a/src/xml/xml_util.cc b/src/xml/xml_util.cc index 7defaa85..038dba05 100644 --- a/src/xml/xml_util.cc +++ b/src/xml/xml_util.cc @@ -169,7 +169,8 @@ static std::string ResolveFilePath(XMLElement* e, std::string filename, // TODO(kylebayes): We first look in the base model directory for files to // remain backwards compatible. std::string full_filename = mjuu_combinePaths(dir, filename); - mjResource *resource = mju_openResource(full_filename.c_str(), nullptr, 0); + mjResource *resource = mju_openResource(full_filename.c_str(), nullptr, + nullptr, 0); if (resource != nullptr) { mju_closeResource(resource); return filename; diff --git a/test/user/user_cache_test.cc b/test/user/user_cache_test.cc index e6111bd5..5b353eac 100644 --- a/test/user/user_cache_test.cc +++ b/test/user/user_cache_test.cc @@ -47,7 +47,7 @@ void CacheText(mjCCache& cache, const std::string& model, mjVFS vfs; mj_defaultVFS(&vfs); mj_addBufferVFS(&vfs, name.c_str(), text.data(), text.size()); - mjResource* resource = mju_openVfsResource(name.c_str(), &vfs); + mjResource* resource = mju_openResource(name.c_str(), &vfs, nullptr, 0); std::shared_ptr data(&text, +[](const void* data) {}); cache.Insert(model, resource, data, text.size()); mju_closeResource(resource); @@ -61,7 +61,7 @@ GetCachedText(mjCCache& cache, const std::string& model, mjVFS vfs; mj_defaultVFS(&vfs); mj_addBufferVFS(&vfs, name.c_str(), text.data(), std::strlen(text.c_str())); - mjResource* resource = mju_openVfsResource(name.c_str(), &vfs); + mjResource* resource = mju_openResource(name.c_str(), &vfs, nullptr, 0); bool inserted = cache.PopulateData(resource, [&cached_text](const void* data) { cached_text = *(static_cast(data)); diff --git a/test/user/user_resource_test.cc b/test/user/user_resource_test.cc index 0f2380d2..3f243641 100644 --- a/test/user/user_resource_test.cc +++ b/test/user/user_resource_test.cc @@ -233,7 +233,7 @@ TEST_F(ResourceTest, GeneralTest) { EXPECT_GT(i, 0); // open resource - mjResource* resource = mju_openResource("str:file", nullptr, 0); + mjResource* resource = mju_openResource("str:file", nullptr, nullptr, 0); ASSERT_THAT(resource, NotNull()); const char* buffer = NULL; @@ -256,7 +256,7 @@ TEST_F(ResourceTest, GeneralFailureTest) { static std::array error; // open resource - mjResource* resource = mju_openResource("str:notfound", + mjResource* resource = mju_openResource("str:notfound", nullptr, error.data(), error.size()); ASSERT_THAT(resource, IsNull()); @@ -281,7 +281,7 @@ TEST_F(ResourceTest, NameWithValidPrefix) { }; // open resource - mjResource* resource = mju_openResource("nop:found", nullptr, 0); + mjResource* resource = mju_openResource("nop:found", nullptr, nullptr, 0); ASSERT_THAT(resource, NotNull()); mju_closeResource(resource); } @@ -304,7 +304,7 @@ TEST_F(ResourceTest, NameWithUpperCasePrefix) { }; // open resource - mjResource* resource = mju_openResource("NOP:found", nullptr, 0); + mjResource* resource = mju_openResource("NOP:found", nullptr, nullptr, 0); ASSERT_THAT(resource, NotNull()); mju_closeResource(resource); } @@ -327,7 +327,7 @@ TEST_F(ResourceTest, NameWithInvalidPrefix) { }; // open resource - mjResource* resource = mju_openResource("nopfound", nullptr, 0); + mjResource* resource = mju_openResource("nopfound", nullptr, nullptr, 0); ASSERT_THAT(resource, IsNull()); } @@ -338,7 +338,8 @@ TEST_F(ResourceTest, OSFilesystemTimestamps) { const char* const file = "engine/testdata/collision_box/boxbox_deep.xml"; const std::string xml_path = GetTestDataFilePath(file); - mjResource* resource = mju_openResource(xml_path.c_str(), nullptr, 0); + mjResource* resource = mju_openResource(xml_path.c_str(), nullptr, + nullptr, 0); mju_decodeBase64((uint8_t*) &t, resource->timestamp); // equal timestamps diff --git a/test/user/user_vfs_test.cc b/test/user/user_vfs_test.cc index b5931ed6..36378130 100644 --- a/test/user/user_vfs_test.cc +++ b/test/user/user_vfs_test.cc @@ -30,7 +30,7 @@ using ::testing::NotNull; using UserVfsTest = MujocoTest; static bool HasFile(const mjVFS* vfs, const std::string& filename) { - mjResource* resource = mju_openVfsResource(filename.c_str(), vfs); + mjResource* resource = mju_openResource(filename.c_str(), vfs, nullptr, 0); bool result = resource != nullptr; mju_closeResource(resource); return result; @@ -222,7 +222,7 @@ TEST_F(UserVfsTest, Timestamps) { mj_defaultVFS(&vfs); mj_addBufferVFS(&vfs, "cube.obj", cube, sizeof(cube)); - mjResource* resource = mju_openVfsResource("cube.obj", &vfs); + mjResource* resource = mju_openResource("cube.obj", &vfs, nullptr, 0); // same timestamps EXPECT_EQ(mju_isModifiedResource(resource, resource->timestamp), 0);