From 8557cf201b94b6381c39c07e64019d7b788ad8c4 Mon Sep 17 00:00:00 2001 From: Haroon Qureshi Date: Sun, 8 Feb 2026 08:07:34 -0800 Subject: [PATCH] Allow root models to be in a subfolder. PiperOrigin-RevId: 867217045 Change-Id: Iae6f7c7f137c2b229b52d93aacea1a4c9e06003e --- src/experimental/mjz/mjz_decoder.cc | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/experimental/mjz/mjz_decoder.cc b/src/experimental/mjz/mjz_decoder.cc index c422cdd1..59ec7656 100644 --- a/src/experimental/mjz/mjz_decoder.cc +++ b/src/experimental/mjz/mjz_decoder.cc @@ -72,6 +72,19 @@ class ZipArchiveProvider : public mjpResourceProvider { files_[stat.m_filename] = FileInfo{i, size, {}}; } + // Look for the root XML model in the archive. First look for an XML file + // with the same name as the archive itself. Failing that, look for an XML + // file with the same name including the parent directory. + const std::filesystem::path path(name_); + root_model_ = (path / path.stem()).string() + ".xml"; + if (!Contains(root_model_)) { + root_model_ = (path / path.parent_path() / path.stem()).string() + ".xml"; + if (!Contains(root_model_)) { + SetError(error, error_sz, "Zip error: no root XML file found."); + return; + } + } + // Setup mjpResourceProvider callbacks. mount = [](mjResource* resource) { return 0; @@ -106,10 +119,7 @@ class ZipArchiveProvider : public mjpResourceProvider { // Returns the path to the root XML model in the archive. std::string GetRootModelPath() const { - // Assumes the root has the same name as the archive itself, but with a .xml - // extension. - const std::filesystem::path path(name_); - return (path / path.stem()).string() + ".xml"; + return root_model_; } // Returns true if the archive contains a file with the given name/path. @@ -154,6 +164,7 @@ class ZipArchiveProvider : public mjpResourceProvider { }; std::string name_; + std::string root_model_; mz_zip_archive archive_; std::vector buffer_; std::unordered_map files_;