diff --git a/src/xml/xml_global.h b/src/xml/xml_global.h index d3b6f41d..758c3214 100644 --- a/src/xml/xml_global.h +++ b/src/xml/xml_global.h @@ -20,7 +20,7 @@ #include -void SetGlobalXmlSpec(mjSpec* spec = nullptr); +MJAPI void SetGlobalXmlSpec(mjSpec* spec = nullptr); std::string GetGlobalXmlSpec(const mjModel* m, char* error, int error_sz); diff --git a/test/fixture.cc b/test/fixture.cc index 79a1e37b..55c1739f 100644 --- a/test/fixture.cc +++ b/test/fixture.cc @@ -41,6 +41,7 @@ #include #include #include +#include "src/xml/xml_global.h" namespace mujoco { namespace { @@ -85,26 +86,27 @@ const std::string GetModelPath(std::string_view path) { // NOLINT mjModel* LoadModelFromString(std::string_view xml, char* error, int error_size, mjVFS* vfs) { - // register string resource provider if not registered before - if (mjp_getResourceProvider("LoadModelFromString:") == nullptr) { - mjpResourceProvider resourceProvider; - mjp_defaultResourceProvider(&resourceProvider); - resourceProvider.prefix = "LoadModelFromString"; - resourceProvider.open = +[](mjResource* resource) { - resource->data = &(resource->name[strlen("LoadModelFromString:")]); - return 1; - }; - resourceProvider.read = - +[](mjResource* resource, const void** buffer) { - *buffer = resource->data; - return (int) strlen((const char*) resource->data); - }; - resourceProvider.close = +[](mjResource* resource) {}; - mjp_registerResourceProvider(&resourceProvider); + if (error) { + error[0] = '\0'; } - std::string xml2 = {xml.begin(), xml.end()}; - std::string str = "LoadModelFromString:" + xml2; - return mj_loadXML(str.c_str(), vfs, error, error_size); + + // This duplicates the logic in mj_loadXML, but allows us to use a string + // directly rather than having to write the contents to a file. Most + // importantly, we "save" the spec to global storage so that subsequent calls + // to mj_saveLastXML will be done using the parsed mjSpec. + mjSpec* spec = mj_parseXMLString(xml.data(), vfs, error, error_size); + + mjModel* model = nullptr; + if (spec) { + model = mj_compile(spec, vfs); + + if (error && (!model || mjs_isWarning(spec))) { + strncpy(error, mjs_getError(spec), error_size); + error[error_size - 1] = '\0'; + } + } + SetGlobalXmlSpec(spec); + return model; } static void AssertModelNotNull(mjModel* model,