Fix bug with absolute meshdirs in included XML files. Fixes #1772.
PiperOrigin-RevId: 649150979 Change-Id: I5df08c689afc4f5bc625e989a8c0b9733fcfa3c2
This commit is contained in:
committed by
Copybara-Service
parent
9107d3b507
commit
2a4410e4e5
@@ -900,7 +900,7 @@ bool mjCFlexcomp::MakeMesh(mjCModel* model, char* error, int error_sz) {
|
||||
}
|
||||
|
||||
// load resource
|
||||
std::string filename = mjuu_makefullname(mjs_getString(model->spec.modelfiledir),
|
||||
std::string filename = mjuu_combinePaths(mjs_getString(model->spec.modelfiledir),
|
||||
mjs_getString(model->spec.meshdir), file);
|
||||
mjResource* resource = nullptr;
|
||||
|
||||
@@ -999,7 +999,7 @@ bool mjCFlexcomp::MakeGMSH(mjCModel* model, char* error, int error_sz) {
|
||||
}
|
||||
|
||||
// open resource
|
||||
std::string filename = mjuu_makefullname(mjs_getString(model->spec.modelfiledir),
|
||||
std::string filename = mjuu_combinePaths(mjs_getString(model->spec.modelfiledir),
|
||||
mjs_getString(model->spec.meshdir), file);
|
||||
mjResource* resource = nullptr;
|
||||
|
||||
|
||||
@@ -368,7 +368,7 @@ void mjCMesh::Compile(const mjVFS* vfs) {
|
||||
throw mjCError(this, "unsupported content type: '%s'", asset_type.c_str());
|
||||
}
|
||||
|
||||
string filename = mjuu_makefullname(model->modelfiledir_, model->meshdir_, file_);
|
||||
string filename = mjuu_combinePaths(model->modelfiledir_, model->meshdir_, file_);
|
||||
mjResource* resource = LoadResource(filename, vfs);
|
||||
|
||||
try {
|
||||
@@ -2091,7 +2091,7 @@ void mjCSkin::Compile(const mjVFS* vfs) {
|
||||
throw mjCError(this, "Unknown skin file type: %s", file_.c_str());
|
||||
}
|
||||
|
||||
string filename = mjuu_makefullname(model->modelfiledir_, model->meshdir_, file_);
|
||||
string filename = mjuu_combinePaths(model->modelfiledir_, model->meshdir_, file_);
|
||||
mjResource* resource = LoadResource(filename, vfs);
|
||||
|
||||
try {
|
||||
|
||||
@@ -3105,7 +3105,7 @@ void mjCHField::Compile(const mjVFS* vfs) {
|
||||
throw mjCError(this, "unsupported content type: '%s'", asset_type.c_str());
|
||||
}
|
||||
|
||||
string filename = mjuu_makefullname(model->modelfiledir_, model->meshdir_, file_);
|
||||
string filename = mjuu_combinePaths(model->modelfiledir_, model->meshdir_, file_);
|
||||
mjResource* resource = LoadResource(filename, vfs);
|
||||
|
||||
try {
|
||||
@@ -3723,7 +3723,7 @@ void mjCTexture::LoadCubeSeparate(const mjVFS* vfs) {
|
||||
}
|
||||
|
||||
// make filename
|
||||
string filename = mjuu_makefullname(model->modelfiledir_, model->texturedir_, cubefiles_[i]);
|
||||
string filename = mjuu_combinePaths(model->modelfiledir_, model->texturedir_, cubefiles_[i]);
|
||||
|
||||
// load PNG or custom
|
||||
unsigned int w, h;
|
||||
@@ -3821,7 +3821,7 @@ void mjCTexture::Compile(const mjVFS* vfs) {
|
||||
}
|
||||
|
||||
// make filename
|
||||
string filename = mjuu_makefullname(model->modelfiledir_, model->texturedir_, file_);
|
||||
string filename = mjuu_combinePaths(model->modelfiledir_, model->texturedir_, file_);
|
||||
|
||||
// dispatch
|
||||
if (type==mjTEXTURE_2D) {
|
||||
|
||||
+18
-11
@@ -837,23 +837,30 @@ bool mjuu_isabspath(string path) {
|
||||
|
||||
|
||||
|
||||
// assemble full filename
|
||||
string mjuu_makefullname(string filedir, string meshdir, string filename) {
|
||||
// filename has absolute path: filename
|
||||
if (mjuu_isabspath(filename)) {
|
||||
return filename;
|
||||
// assemble two file paths
|
||||
std::string mjuu_combinePaths(const string& path1, const string& path2) {
|
||||
// path2 has absolute path
|
||||
if (mjuu_isabspath(path2)) {
|
||||
return path2;
|
||||
}
|
||||
|
||||
// meshdir has absolute path: meshdir + filename
|
||||
if (mjuu_isabspath(meshdir)) {
|
||||
return meshdir + filename;
|
||||
std::size_t n = path1.size();
|
||||
if (n > 0 && path1[n - 1] != '\\' && path1[n - 1] != '/') {
|
||||
return path1 + "/" + path2;
|
||||
}
|
||||
|
||||
// default
|
||||
return filedir + meshdir + filename;
|
||||
return path1 + path2;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// assemble three file paths
|
||||
std::string mjuu_combinePaths(const string& path1, const string& path2,
|
||||
const string& path3) {
|
||||
return mjuu_combinePaths(path1, mjuu_combinePaths(path2, path3));
|
||||
}
|
||||
|
||||
|
||||
|
||||
// return true if the text is in a valid content type format:
|
||||
// {type}/{subtype}[;{parameter}={value}]
|
||||
static bool mjuu_isValidContentType(std::string_view text) {
|
||||
|
||||
@@ -167,8 +167,10 @@ std::string mjuu_getext(std::string_view filename);
|
||||
// check if path is absolute
|
||||
bool mjuu_isabspath(std::string path);
|
||||
|
||||
// assemble full filename
|
||||
std::string mjuu_makefullname(std::string filedir, std::string meshdir, std::string filename);
|
||||
// assemble file paths
|
||||
std::string mjuu_combinePaths(const std::string& path1, const std::string& path2);
|
||||
std::string mjuu_combinePaths(const std::string& path1, const std::string& path2,
|
||||
const std::string& path3);
|
||||
|
||||
// return type from content_type format {type}/{subtype}[;{parameter}={value}]
|
||||
std::optional<std::string_view> mjuu_parseContentTypeAttrType(std::string_view text);
|
||||
|
||||
@@ -4120,56 +4120,36 @@ mjsDefault* mjXReader::GetClass(XMLElement* section) {
|
||||
return def;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// return true if c is a directory path separator (i.e. '/' or '\' on windows)
|
||||
static bool IsSeperator(char c) {
|
||||
return c == '/' || c == '\\';
|
||||
}
|
||||
|
||||
void mjXReader::SetModelFileDir(std::string modelfiledir) {
|
||||
modelfiledir_ = modelfiledir;
|
||||
if (!modelfiledir_.empty() && !IsSeperator(modelfiledir_.back())) {
|
||||
modelfiledir_.append("/");
|
||||
}
|
||||
}
|
||||
|
||||
void mjXReader::SetAssetDir(std::string assetdir) {
|
||||
assetdir_ = assetdir;
|
||||
if (!assetdir_.empty() && !IsSeperator(assetdir_.back())) {
|
||||
assetdir_.append("/");
|
||||
}
|
||||
}
|
||||
|
||||
void mjXReader::SetMeshDir(std::string meshdir) {
|
||||
meshdir_ = meshdir;
|
||||
if (!meshdir_.empty() && !IsSeperator(meshdir_.back())) {
|
||||
meshdir_.append("/");
|
||||
}
|
||||
}
|
||||
|
||||
void mjXReader::SetTextureDir(std::string texturedir) {
|
||||
texturedir_ = texturedir;
|
||||
if (!texturedir_.empty() && !IsSeperator(texturedir_.back())) {
|
||||
texturedir_.append("/");
|
||||
}
|
||||
}
|
||||
|
||||
std::string mjXReader::AssetDir() const {
|
||||
return modelfiledir_ + assetdir_;
|
||||
return mjuu_combinePaths(modelfiledir_, assetdir_);
|
||||
}
|
||||
|
||||
std::string mjXReader::MeshDir() const {
|
||||
if (meshdir_.empty()) {
|
||||
return AssetDir();
|
||||
}
|
||||
return modelfiledir_ + meshdir_;
|
||||
return mjuu_combinePaths(modelfiledir_, meshdir_);
|
||||
}
|
||||
|
||||
std::string mjXReader::TextureDir() const {
|
||||
if (texturedir_.empty()) {
|
||||
return AssetDir();
|
||||
}
|
||||
return modelfiledir_ + texturedir_;
|
||||
return mjuu_combinePaths(modelfiledir_, texturedir_);
|
||||
}
|
||||
|
||||
+2
-2
@@ -168,7 +168,7 @@ 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 = dir + filename;
|
||||
std::string full_filename = mjuu_combinePaths(dir, filename);
|
||||
mjResource *resource = mju_openResource(full_filename.c_str(), nullptr, 0);
|
||||
if (resource != nullptr) {
|
||||
mju_closeResource(resource);
|
||||
@@ -185,7 +185,7 @@ static std::string ResolveFilePath(XMLElement* e, std::string filename,
|
||||
break;
|
||||
}
|
||||
}
|
||||
return path + filename;
|
||||
return mjuu_combinePaths(path, filename);
|
||||
}
|
||||
|
||||
// constructor
|
||||
|
||||
@@ -906,6 +906,47 @@ TEST_F(XMLReaderTest, IncludeAbsoluteTest) {
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
TEST_F(XMLReaderTest, IncludeAbsoluteMeshDirTest) {
|
||||
static constexpr char xml[] = R"(
|
||||
<mujoco>
|
||||
<include file="assets.xml"/>
|
||||
</mujoco>
|
||||
)";
|
||||
static constexpr char assets[] = R"(
|
||||
<mujoco>
|
||||
<compiler meshdir="mjMock.IncludeAbsoluteMeshDirTest:/assets"/>
|
||||
<asset>
|
||||
<mesh file="cube.obj"/>
|
||||
</asset>
|
||||
</mujoco>
|
||||
)";
|
||||
|
||||
static constexpr char cube[] = R"(
|
||||
v -0.500000 -0.500000 0.500000
|
||||
v 0.500000 -0.500000 0.500000
|
||||
v -0.500000 0.500000 0.500000
|
||||
v 0.500000 0.500000 0.500000
|
||||
v -0.500000 0.500000 -0.500000
|
||||
v 0.500000 0.500000 -0.500000
|
||||
v -0.500000 -0.500000 -0.500000
|
||||
v 0.500000 -0.500000 -0.500000)";
|
||||
|
||||
MockFilesystem fs("IncludeAbsoluteMeshDirTest");
|
||||
fs.AddFile("/assets/cube.obj", (const unsigned char*) cube, sizeof(cube));
|
||||
fs.AddFile("assets.xml", (const unsigned char*) assets,
|
||||
sizeof(assets));
|
||||
fs.AddFile("model.xml", (const unsigned char*) xml, sizeof(xml));
|
||||
std::string modelpath = fs.FullPath("model.xml");
|
||||
|
||||
std::array<char, 1024> error;
|
||||
// loading the file should be successful
|
||||
mjModel* model = mj_loadXML(modelpath.c_str(), nullptr,
|
||||
error.data(), error.size());
|
||||
ASSERT_THAT(model, NotNull()) << "Failed to load model: " << error.data();
|
||||
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
TEST_F(XMLReaderTest, ParsePolycoef) {
|
||||
static constexpr char xml[] = R"(
|
||||
<mujoco>
|
||||
|
||||
Reference in New Issue
Block a user