Support directories in VFS via mj_addBufferVFS.

PiperOrigin-RevId: 655286683
Change-Id: I846376a0571d8df28d979beb5981a0cbccd7a04f
This commit is contained in:
Kyle Bayes
2024-07-23 13:38:28 -07:00
committed by Copybara-Service
parent 2746cb8559
commit 5ac5cfb618
18 changed files with 197 additions and 156 deletions
+6 -7
View File
@@ -900,12 +900,12 @@ bool mjCFlexcomp::MakeMesh(mjCModel* model, char* error, int error_sz) {
}
// load resource
std::string filename = mjuu_combinePaths(mjs_getString(model->spec.modelfiledir),
mjs_getString(model->spec.meshdir), file);
std::string filename = mjuu_combinePaths(mjs_getString(model->spec.meshdir), file);
mjResource* resource = nullptr;
try {
resource = mjCBase::LoadResource(filename, 0);
resource = mjCBase::LoadResource(mjs_getString(model->spec.modelfiledir),
filename, 0);
} catch (mjCError err) {
return comperr(error, err.message, error_sz);
}
@@ -999,12 +999,11 @@ bool mjCFlexcomp::MakeGMSH(mjCModel* model, char* error, int error_sz) {
}
// open resource
std::string filename = mjuu_combinePaths(mjs_getString(model->spec.modelfiledir),
mjs_getString(model->spec.meshdir), file);
mjResource* resource = nullptr;
try {
resource = mjCBase::LoadResource(filename, 0);
std::string filename = mjuu_combinePaths(mjs_getString(model->spec.meshdir), file);
resource = mjCBase::LoadResource(mjs_getString(model->spec.modelfiledir),
filename, 0);
} catch (mjCError err) {
return comperr(error, err.message, error_sz);
}
+4 -4
View File
@@ -402,8 +402,8 @@ void mjCMesh::Compile(const mjVFS* vfs) {
throw mjCError(this, "unsupported content type: '%s'", asset_type.c_str());
}
std::string filename = mjuu_combinePaths(model->modelfiledir_, model->meshdir_, file_);
mjResource* resource = LoadResource(filename, vfs);
std::string filename = mjuu_combinePaths(model->meshdir_, file_);
mjResource* resource = LoadResource(model->modelfiledir_, filename, vfs);
try {
if (asset_type == "model/stl") {
@@ -2095,8 +2095,8 @@ void mjCSkin::Compile(const mjVFS* vfs) {
throw mjCError(this, "Unknown skin file type: %s", file_.c_str());
}
std::string filename = mjuu_combinePaths(model->modelfiledir_, model->meshdir_, file_);
mjResource* resource = LoadResource(filename, vfs);
std::string filename = mjuu_combinePaths(model->meshdir_, file_);
mjResource* resource = LoadResource(model->modelfiledir_, filename, vfs);
try {
LoadSKN(resource);
+9 -7
View File
@@ -701,10 +701,12 @@ void mjCBase::NameSpace(const mjCModel* m) {
// load resource if found (fallback to OS filesystem)
mjResource* mjCBase::LoadResource(std::string filename, const mjVFS* vfs) {
mjResource* mjCBase::LoadResource(const std::string& modelfiledir,
const std::string& filename,
const mjVFS* vfs) {
// try reading from provided VFS or fallback to OS filesystem
std::array<char, 1024> error;
mjResource* resource = mju_openResource(filename.c_str(), vfs,
mjResource* resource = mju_openResource(modelfiledir.c_str(), filename.c_str(), vfs,
error.data(), error.size());
if (!resource) {
throw mjCError(nullptr, "%s", error.data());
@@ -3159,8 +3161,8 @@ void mjCHField::Compile(const mjVFS* vfs) {
throw mjCError(this, "unsupported content type: '%s'", asset_type.c_str());
}
std::string filename = mjuu_combinePaths(model->modelfiledir_, model->meshdir_, file_);
mjResource* resource = LoadResource(filename, vfs);
std::string filename = mjuu_combinePaths(model->meshdir_, file_);
mjResource* resource = LoadResource(model->modelfiledir_, filename, vfs);
try {
if (asset_type == "image/png") {
@@ -3594,7 +3596,7 @@ void mjCTexture::LoadFlip(std::string filename, const mjVFS* vfs,
throw mjCError(this, "unsupported content type: '%s'", asset_type.c_str());
}
mjResource* resource = LoadResource(filename, vfs);
mjResource* resource = LoadResource(model->modelfiledir_, filename, vfs);
try {
if (asset_type == "image/png") {
@@ -3797,7 +3799,7 @@ void mjCTexture::LoadCubeSeparate(const mjVFS* vfs) {
}
// make filename
std::string filename = mjuu_combinePaths(model->modelfiledir_, model->texturedir_, cubefiles_[i]);
std::string filename = mjuu_combinePaths(model->texturedir_, cubefiles_[i]);
// load PNG or custom
unsigned int w, h;
@@ -3895,7 +3897,7 @@ void mjCTexture::Compile(const mjVFS* vfs) {
}
// make filename
std::string filename = mjuu_combinePaths(model->modelfiledir_, model->texturedir_, file_);
std::string filename = mjuu_combinePaths(model->texturedir_, file_);
// dispatch
if (type==mjTEXTURE_2D) {
+2 -1
View File
@@ -181,7 +181,8 @@ class mjCBase : public mjCBase_ {
public:
// load resource if found (fallback to OS filesystem)
static mjResource* LoadResource(std::string filename, const mjVFS* vfs);
static mjResource* LoadResource(const std::string& modelfiledir,
const std::string& filename, const mjVFS* vfs);
// Get and sanitize content type from raw_text if not empty, otherwise parse
// content type from resource_name; throw on failure
+14 -7
View File
@@ -23,6 +23,7 @@
#include <cstdio>
#include <cstring>
#include <ctime>
#include <string>
#include <vector>
#if defined (__unix__) || (defined (__APPLE__) && defined (__MACH__))
@@ -117,8 +118,8 @@ int FileModified(const mjResource* resource, const char*timestamp) {
// 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, const mjVFS* vfs,
char* error, size_t nerror) {
mjResource* mju_openResource(const char* dir, const char* name,
const mjVFS* vfs, char* error, size_t nerror) {
// no error so far
if (error) {
error[0] = '\0';
@@ -136,8 +137,10 @@ mjResource* mju_openResource(const char* name, const mjVFS* vfs,
// clear out resource
memset(resource, 0, sizeof(mjResource));
// copy name
resource->name = (char*) mju_malloc(sizeof(char) * (strlen(name) + 1));
// make space for filename
std::string fullname = mjuu_combinePaths(dir, name);
std::size_t n = fullname.size();
resource->name = (char*) mju_malloc(sizeof(char) * (n + 1));
if (resource->name == nullptr) {
if (error) {
strncpy(error, "could not allocate memory", nerror);
@@ -146,10 +149,11 @@ mjResource* mju_openResource(const char* name, const mjVFS* vfs,
mju_closeResource(resource);
return nullptr;
}
memcpy(resource->name, name, sizeof(char) * (strlen(name) + 1));
// first priority is to check the VFS
if (vfs != nullptr) {
memcpy(resource->name, name,
sizeof(char) * (std::strlen(name) + 1));
const mjpResourceProvider* provider = GetVfsResourceProvider();
resource->data = (void*) vfs;
resource->provider = provider;
@@ -158,8 +162,11 @@ mjResource* mju_openResource(const char* name, const mjVFS* vfs,
}
}
// copy full path over
memcpy(resource->name, fullname.c_str(), sizeof(char) * (n + 1));
// find provider based off prefix of name
const mjpResourceProvider* provider = mjp_getResourceProvider(name);
const mjpResourceProvider* provider = mjp_getResourceProvider(resource->name);
if (provider != nullptr) {
resource->provider = provider;
resource->data = nullptr;
@@ -170,7 +177,7 @@ mjResource* mju_openResource(const char* name, const mjVFS* vfs,
if (error) {
snprintf(error, nerror, "could not open '%s'"
"using a resource provider matching prefix '%s'",
name, provider->prefix);
resource->name, provider->prefix);
}
mju_closeResource(resource);
+2 -4
View File
@@ -18,8 +18,6 @@
#define MUJOCO_SRC_ENGINE_ENGINE_RESOURCE_H_
#include <cstddef>
#include <cstdint>
#include <vector>
#include <mujoco/mjexport.h>
#include <mujoco/mujoco.h>
@@ -30,8 +28,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, const mjVFS* vfs,
char* error, std::size_t nerror);
MJAPI mjResource* mju_openResource(const char* dir, const char* name,
const mjVFS* vfs, char* error, size_t nerror);
// close the given resource; no-op if resource is NULL
MJAPI void mju_closeResource(mjResource* resource);
+12 -7
View File
@@ -142,9 +142,13 @@ int Open(mjResource* resource) {
const VFS* cvfs = GetVFSImpl(vfs);
const VFSFile* file = cvfs->GetFile(StripPath(resource->name));
if (file == nullptr) {
return 0;
file = cvfs->GetFile(FilePath(resource->name));
if (file == nullptr) {
return 0;
}
}
resource->data = (void*) file;
resource->timestamp[0] = '\0';
if (file->filestamp) {
mju_encodeBase64(resource->timestamp, (uint8_t*) &file->filestamp,
@@ -160,8 +164,7 @@ int Read(mjResource* resource, const void** buffer) {
return -1;
}
const VFS* vfs = GetVFSImpl(static_cast<const mjVFS*>(resource->data));
const VFSFile* file = vfs->GetFile(StripPath(resource->name));
const VFSFile* file = static_cast<const VFSFile*>(resource->data);
if (file == nullptr) {
*buffer = nullptr;
return -1;
@@ -193,8 +196,7 @@ int Modified(const mjResource* resource, const char* timestamp) {
if (!filestamp) return 3; // no hash (assume modified)
if (resource) {
const VFS* cvfs = GetVFSImpl(static_cast<const mjVFS*>(resource->data));
const VFSFile* file = cvfs->GetFile(StripPath(resource->name));
const VFSFile* file = static_cast<const VFSFile*>(resource->data);
if (file == nullptr) return 4; // missing file (assume modified)
if (!file->filestamp) return 5; // missing filestamp (assume modified)
@@ -245,7 +247,7 @@ int mj_addBufferVFS(mjVFS* vfs, const char* name, const void* buffer,
std::vector<uint8_t> inbuffer;
VFS* cvfs = GetVFSImpl(vfs);
VFSFile* file;
if (!(file = cvfs->AddFile(StripPath(name), std::move(inbuffer), 0))) {
if (!(file = cvfs->AddFile(FilePath(name), std::move(inbuffer), 0))) {
return 2; // AddFile failed, repeated name
}
file->filedata.reserve(nbuffer);
@@ -256,7 +258,10 @@ int mj_addBufferVFS(mjVFS* vfs, const char* name, const void* buffer,
// delete file from VFS, return 0: success, -1: not found in VFS
int mj_deleteFileVFS(mjVFS* vfs, const char* filename) {
VFS* cvfs = GetVFSImpl(vfs);
return cvfs->DeleteFile(StripPath(filename));
if (cvfs->DeleteFile(StripPath(filename))) {
return cvfs->DeleteFile(FilePath(filename));
}
return 0;
}
// delete all files from VFS
+9 -10
View File
@@ -156,8 +156,8 @@ void IncludeXML(mjXReader& reader, XMLElement* elem,
}
// get filename
auto file_attr = mjXUtil::ReadAttrFile(elem, "file", reader.ModelFileDir(),
true);
auto file_attr = mjXUtil::ReadAttrFile(elem, "file", vfs,
reader.ModelFileDir(), true);
if (!file_attr.has_value()) {
throw mjXError(elem, "Include element missing file attribute");
}
@@ -171,17 +171,17 @@ void IncludeXML(mjXReader& reader, XMLElement* elem,
// TODO: b/325905702 - We have a messy wrapper here to remain backwards
// compatible, which will be removed in the near future.
FilePath fullname = reader.ModelFileDir() + filename;
// legacy behavior: try to load in top level directory
std::array<char, 1024> error;
mjResource *resource = mju_openResource(fullname.c_str(), vfs,
mjResource *resource = mju_openResource(reader.ModelFileDir().c_str(),
filename.c_str(), vfs,
error.data(), error.size());
if (resource == nullptr) {
// new behavior: try to load in relative directory
if (!filename.IsAbs()) {
fullname = dir + filename;
resource = mju_openResource(fullname.c_str(), vfs, error.data(), error.size());
FilePath fullname = dir + filename;
resource = mju_openResource(reader.ModelFileDir().c_str(),
fullname.c_str(), vfs, error.data(), error.size());
}
}
@@ -195,7 +195,6 @@ void IncludeXML(mjXReader& reader, XMLElement* elem,
int ninclude_dir = 0;
mju_getResourceDir(resource, &include_dir, &ninclude_dir);
FilePath next_dir = FilePath(std::string(include_dir, ninclude_dir));
next_dir = dir + next_dir;
elem->SetAttribute("dir", next_dir.c_str());
const char* xmlstring = nullptr;
@@ -285,7 +284,7 @@ mjSpec* ParseXML(const char* filename, const mjVFS* vfs,
// get data source
const char* xmlstring = nullptr;
std::array<char, 1024> rerror;
mjResource* resource = mju_openResource(filename, vfs,
mjResource* resource = mju_openResource("", filename, vfs,
rerror.data(), rerror.size());
if (resource == nullptr) {
std::snprintf(error, nerror, "ParseXML: %s", rerror.data());
@@ -352,7 +351,7 @@ mjSpec* ParseXML(const char* filename, const mjVFS* vfs,
std::unordered_set<std::string> included = {filename};
mjXReader parser;
parser.SetModelFileDir(mjs_getString(spec->modelfiledir));
IncludeXML(parser, root, parser.ModelFileDir(), vfs, included);
IncludeXML(parser, root, FilePath(), vfs, included);
// parse MuJoCo model
parser.SetModel(spec);
+1 -1
View File
@@ -192,7 +192,7 @@ 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) {
std::array<char, 1024> error;
mjResource* resource = mju_openResource(filename, vfs,
mjResource* resource = mju_openResource("", filename, vfs,
error.data(), error.size());
if (resource == nullptr) {
mju_warning("%s", error.data());
+26 -25
View File
@@ -893,7 +893,7 @@ void mjXReader::Parse(XMLElement* root, const mjVFS* vfs) {
readingdefaults = true;
for (XMLElement* section = FirstChildElement(root, "default"); section;
section = NextSiblingElement(section, "default")) {
Default(section, nullptr);
Default(section, nullptr, vfs);
}
readingdefaults = false;
@@ -919,7 +919,7 @@ void mjXReader::Parse(XMLElement* root, const mjVFS* vfs) {
for (XMLElement* section = FirstChildElement(root, "deformable"); section;
section = NextSiblingElement(section, "deformable")) {
Deformable(section);
Deformable(section, vfs);
}
for (XMLElement* section = FirstChildElement(root, "equality"); section;
@@ -949,7 +949,7 @@ void mjXReader::Parse(XMLElement* root, const mjVFS* vfs) {
for (XMLElement* section = FirstChildElement(root, "worldbody"); section;
section = NextSiblingElement(section, "worldbody")) {
Body(section, mjs_findBody(spec, "world"), nullptr);
Body(section, mjs_findBody(spec, "world"), nullptr, vfs);
}
}
@@ -1389,7 +1389,7 @@ void mjXReader::OneFlex(XMLElement* elem, mjsFlex* pflex) {
// mesh element parser
void mjXReader::OneMesh(XMLElement* elem, mjsMesh* pmesh) {
void mjXReader::OneMesh(XMLElement* elem, mjsMesh* pmesh, const mjVFS* vfs) {
int n;
string text, name, content_type;
@@ -1400,7 +1400,7 @@ void mjXReader::OneMesh(XMLElement* elem, mjsMesh* pmesh) {
if (ReadAttrTxt(elem, "content_type", content_type)) {
*pmesh->content_type = content_type;
}
auto file = ReadAttrFile(elem, "file", MeshDir());
auto file = ReadAttrFile(elem, "file", vfs, MeshDir());
if (file) {
mjs_setString(pmesh->file, file->c_str());
}
@@ -1461,7 +1461,7 @@ void mjXReader::OneMesh(XMLElement* elem, mjsMesh* pmesh) {
// skin element parser
void mjXReader::OneSkin(XMLElement* elem, mjsSkin* pskin) {
void mjXReader::OneSkin(XMLElement* elem, mjsSkin* pskin, const mjVFS* vfs) {
string text, name, material;
float data[4];
@@ -1469,7 +1469,7 @@ void mjXReader::OneSkin(XMLElement* elem, mjsSkin* pskin) {
if (ReadAttrTxt(elem, "name", name)) {
mjs_setString(pskin->name, name.c_str());
}
auto file = ReadAttrFile(elem, "file", AssetDir());
auto file = ReadAttrFile(elem, "file", vfs, AssetDir());
if (file.has_value()) {
mjs_setString(pskin->file, file->c_str());
}
@@ -2536,7 +2536,7 @@ void mjXReader::OneComposite(XMLElement* elem, mjsBody* pbody, mjsDefault* def)
// make flexcomp
void mjXReader::OneFlexcomp(XMLElement* elem, mjsBody* pbody) {
void mjXReader::OneFlexcomp(XMLElement* elem, mjsBody* pbody, const mjVFS* vfs) {
string text, material;
int n;
@@ -2554,7 +2554,7 @@ void mjXReader::OneFlexcomp(XMLElement* elem, mjsBody* pbody) {
ReadAttr(elem, "scale", 3, fcomp.scale, text);
ReadAttr(elem, "mass", 1, &fcomp.mass, text);
ReadAttr(elem, "inertiabox", 1, &fcomp.inertiabox, text);
auto maybe_file = ReadAttrFile(elem, "file", modelfiledir_);
auto maybe_file = ReadAttrFile(elem, "file", vfs, modelfiledir_);
if (maybe_file.has_value()) {
fcomp.file = std::move(maybe_file.value().Str());
} else {
@@ -2690,7 +2690,7 @@ void mjXReader::OnePlugin(XMLElement* elem, mjsPlugin* plugin) {
//------------------ MJCF-specific sections --------------------------------------------------------
// default section parser
void mjXReader::Default(XMLElement* section, const mjsDefault* def) {
void mjXReader::Default(XMLElement* section, const mjsDefault* def, const mjVFS* vfs) {
XMLElement* elem;
string text, name;
@@ -2721,7 +2721,7 @@ void mjXReader::Default(XMLElement* section, const mjsDefault* def) {
name = elem->Value();
// read mesh
if (name=="mesh") OneMesh(elem, def->mesh);
if (name=="mesh") OneMesh(elem, def->mesh, vfs);
// read material
else if (name=="material") OneMaterial(elem, def->material);
@@ -2775,7 +2775,7 @@ void mjXReader::Default(XMLElement* section, const mjsDefault* def) {
// read default
if (name=="default") {
Default(elem, def);
Default(elem, def, vfs);
}
// advance
@@ -3136,7 +3136,7 @@ void mjXReader::Asset(XMLElement* section, const mjVFS* vfs) {
if (ReadAttrTxt(elem, "content_type", content_type)) {
mjs_setString(ptex->content_type, content_type.c_str());
}
auto file = ReadAttrFile(elem, "file", TextureDir());
auto file = ReadAttrFile(elem, "file", vfs, TextureDir());
if (file.has_value()) {
mjs_setString(ptex->file, file->c_str());
}
@@ -3182,7 +3182,7 @@ void mjXReader::Asset(XMLElement* section, const mjVFS* vfs) {
"fileup", "filedown",
"filefront", "fileback"};
for (int i = 0; i < cubefiles.size(); i++) {
auto maybe_file = ReadAttrFile(elem, cubefile_names[i].c_str(),
auto maybe_file = ReadAttrFile(elem, cubefile_names[i].c_str(), vfs,
TextureDir());
if (maybe_file.has_value()) {
cubefiles[i] = maybe_file.value().Str();
@@ -3204,14 +3204,14 @@ void mjXReader::Asset(XMLElement* section, const mjVFS* vfs) {
else if (name=="mesh") {
// create mesh and parse
mjsMesh* pmesh = mjs_addMesh(spec, def);
OneMesh(elem, pmesh);
OneMesh(elem, pmesh, vfs);
}
// skin sub-element... deprecate ???
else if (name=="skin") {
// create skin and parse
mjsSkin* pskin = mjs_addSkin(spec);
OneSkin(elem, pskin);
OneSkin(elem, pskin, vfs);
}
// hfield sub-element
@@ -3230,7 +3230,7 @@ void mjXReader::Asset(XMLElement* section, const mjVFS* vfs) {
if (ReadAttrTxt(elem, "content_type", content_type)) {
mjs_setString(phf->content_type, content_type.c_str());
}
auto file = ReadAttrFile(elem, "file", AssetDir());
auto file = ReadAttrFile(elem, "file", vfs, AssetDir());
if (file.has_value()) {
mjs_setString(phf->file, file->c_str());
}
@@ -3274,7 +3274,7 @@ void mjXReader::Asset(XMLElement* section, const mjVFS* vfs) {
// model sub-element
else if (name=="model") {
auto filename = modelfiledir_ + ReadAttrFile(elem, "file").value();
auto filename = modelfiledir_ + ReadAttrFile(elem, "file", vfs).value();
// parse the child
std::array<char, 1024> error;
@@ -3301,7 +3301,8 @@ void mjXReader::Asset(XMLElement* section, const mjVFS* vfs) {
// body/world section parser; recursive
void mjXReader::Body(XMLElement* section, mjsBody* pbody, mjsFrame* frame) {
void mjXReader::Body(XMLElement* section, mjsBody* pbody, mjsFrame* frame,
const mjVFS* vfs) {
string text, name;
XMLElement* elem;
int n;
@@ -3427,7 +3428,7 @@ void mjXReader::Body(XMLElement* section, mjsBody* pbody, mjsFrame* frame) {
// flexcomp sub-element
else if (name=="flexcomp") {
// parse flexcomp
OneFlexcomp(elem, pbody);
OneFlexcomp(elem, pbody, vfs);
}
// frame sub-element
@@ -3459,7 +3460,7 @@ void mjXReader::Body(XMLElement* section, mjsBody* pbody, mjsFrame* frame) {
ReadQuat(elem, "quat", pframe->quat, text);
ReadAlternative(elem, pframe->alt);
Body(elem, pbody, pframe);
Body(elem, pbody, pframe, vfs);
}
// replicate sub-element
@@ -3518,7 +3519,7 @@ void mjXReader::Body(XMLElement* section, mjsBody* pbody, mjsFrame* frame) {
UpdateString(suffix, count, i);
// process subtree
Body(elem, subtree, pframe);
Body(elem, subtree, pframe, vfs);
// attach to parent
if (mjs_attachFrame(pbody, pframe, /*prefix=*/"", suffix.c_str()) != 0) {
@@ -3577,7 +3578,7 @@ void mjXReader::Body(XMLElement* section, mjsBody* pbody, mjsFrame* frame) {
mjs_setFrame(pchild->element, frame);
// make recursive call
Body(elem, pchild, nullptr);
Body(elem, pchild, nullptr, vfs);
}
// attachment
@@ -3695,7 +3696,7 @@ void mjXReader::Equality(XMLElement* section) {
// deformable section parser
void mjXReader::Deformable(XMLElement* section) {
void mjXReader::Deformable(XMLElement* section, const mjVFS* vfs) {
string name;
XMLElement* elem;
@@ -3722,7 +3723,7 @@ void mjXReader::Deformable(XMLElement* section) {
else if (name=="skin") {
// create skin and parse
mjsSkin* pskin = mjs_addSkin(spec);
OneSkin(elem, pskin);
OneSkin(elem, pskin, vfs);
}
// advance to next element
+7 -6
View File
@@ -49,16 +49,17 @@ class mjXReader : public mjXBase {
private:
// XML section specific to MJCF
void Default(tinyxml2::XMLElement* section, const mjsDefault* def); // default section
void Default(tinyxml2::XMLElement* section, const mjsDefault* def,
const mjVFS* vfs); // default section
void Extension(tinyxml2::XMLElement* section); // extension section
void Custom(tinyxml2::XMLElement* section); // custom section
void Visual(tinyxml2::XMLElement* section); // visual section
void Statistic(tinyxml2::XMLElement* section); // statistic section
void Asset(tinyxml2::XMLElement* section, const mjVFS* vfs); // asset section
void Body(tinyxml2::XMLElement* section, mjsBody* pbody,
mjsFrame* pframe); // body/world section
mjsFrame* pframe, const mjVFS* vfs); // body/world section
void Contact(tinyxml2::XMLElement* section); // contact section
void Deformable(tinyxml2::XMLElement* section); // deformable section
void Deformable(tinyxml2::XMLElement* section, const mjVFS* vfs); // deformable section
void Equality(tinyxml2::XMLElement* section); // equality section
void Tendon(tinyxml2::XMLElement* section); // tendon section
void Actuator(tinyxml2::XMLElement* section); // actuator section
@@ -67,8 +68,8 @@ class mjXReader : public mjXBase {
// single element parsers, used in defaults and main body
void OneFlex(tinyxml2::XMLElement* elem, mjsFlex* pflex);
void OneMesh(tinyxml2::XMLElement* elem, mjsMesh* pmesh);
void OneSkin(tinyxml2::XMLElement* elem, mjsSkin* pskin);
void OneMesh(tinyxml2::XMLElement* elem, mjsMesh* pmesh, const mjVFS* vfs);
void OneSkin(tinyxml2::XMLElement* elem, mjsSkin* pskin, const mjVFS* vfs);
void OneMaterial(tinyxml2::XMLElement* elem, mjsMaterial* pmaterial);
void OneJoint(tinyxml2::XMLElement* elem, mjsJoint* pjoint);
void OneGeom(tinyxml2::XMLElement* elem, mjsGeom* pgeom);
@@ -80,7 +81,7 @@ class mjXReader : public mjXBase {
void OneTendon(tinyxml2::XMLElement* elem, mjsTendon* ptendon);
void OneActuator(tinyxml2::XMLElement* elem, mjsActuator* pactuator);
void OneComposite(tinyxml2::XMLElement* elem, mjsBody* pbody, mjsDefault* def);
void OneFlexcomp(tinyxml2::XMLElement* elem, mjsBody* pbody);
void OneFlexcomp(tinyxml2::XMLElement* elem, mjsBody* pbody, const mjVFS* vfs);
void OnePlugin(tinyxml2::XMLElement* elem, mjsPlugin* plugin);
mjXSchema schema; // schema used for validation
+4 -4
View File
@@ -76,7 +76,7 @@ static std::optional<T> ParseInfOrNan(const std::string& s) {
}
FilePath ResolveFilePath(XMLElement* e, const FilePath& filename,
const FilePath& dir) {
const FilePath& dir, const mjVFS* vfs) {
std::string path = "";
if (filename.IsAbs()) {
return filename;
@@ -85,7 +85,7 @@ FilePath ResolveFilePath(XMLElement* e, const FilePath& filename,
// TODO(kylebayes): We first look in the base model directory for files to
// remain backwards compatible.
FilePath fullname = dir + filename;
mjResource *resource = mju_openResource(fullname.c_str(), nullptr,
mjResource *resource = mju_openResource("", fullname.c_str(), vfs,
nullptr, 0);
if (resource != nullptr) {
mju_closeResource(resource);
@@ -623,14 +623,14 @@ mjXUtil::ReadAttrStr(XMLElement* elem, const char* attr, bool required) {
// if attribute is present, return attribute as a filename
std::optional<FilePath>
mjXUtil::ReadAttrFile(XMLElement* elem, const char* attr,
mjXUtil::ReadAttrFile(XMLElement* elem, const char* attr, const mjVFS* vfs,
const FilePath& dir, bool required) {
auto maybe_str = ReadAttrStr(elem, attr, required);
if (!maybe_str.has_value()) {
return std::nullopt;
}
FilePath filename(maybe_str.value());
return ResolveFilePath(elem, filename, dir);
return ResolveFilePath(elem, filename, dir, vfs);
}
// if attribute is present, return numerical value of attribute
+2
View File
@@ -26,6 +26,7 @@
#include "tinyxml2.h"
#include <mujoco/mujoco.h>
#include "user/user_util.h"
// error string copy
@@ -114,6 +115,7 @@ class mjXUtil {
// if attribute is present, return attribute as a filename
static std::optional<mujoco::user::FilePath>
ReadAttrFile(tinyxml2::XMLElement* elem, const char* attr,
const mjVFS* vfs,
const mujoco::user::FilePath& dir = mujoco::user::FilePath(),
bool required = false);