Ensure parsing always has a valid VFS.
Explicitly free allocated memory for local resources. (Upcoming changes to `mju_closeResource` will not work for local resources.) PiperOrigin-RevId: 854254013 Change-Id: I5cbb8264b590327767d5500f0c2a32ebe036bc4f
This commit is contained in:
committed by
Copybara-Service
parent
e37c2268a6
commit
9e9314a4a4
+20
-5
@@ -67,20 +67,36 @@ mjSpec* mj_copySpec(const mjSpec* s) {
|
||||
// parse file into spec
|
||||
mjSpec* mj_parse(const char* filename, const char* content_type,
|
||||
const mjVFS* vfs, char* error, int error_sz) {
|
||||
mjVFS local_vfs;
|
||||
mujoco::user::Cleanup cleanup;
|
||||
|
||||
// early exit for existing XML workflow
|
||||
auto filepath = mujoco::user::FilePath(filename);
|
||||
if (filepath.Ext() == ".xml" || (content_type && std::strcmp(content_type, "text/xml") == 0)) {
|
||||
return mj_parseXML(filename, vfs, error, error_sz);
|
||||
}
|
||||
|
||||
// If no VFS is provided, we'll create our own temporary one for the duration
|
||||
// of this function.
|
||||
if (vfs == nullptr) {
|
||||
mj_defaultVFS(&local_vfs);
|
||||
cleanup += [&local_vfs](){ mj_deleteVFS(&local_vfs); };
|
||||
|
||||
vfs = &local_vfs;
|
||||
}
|
||||
|
||||
mjResource* resource = mju_openResource("", filename, vfs, error, error_sz);
|
||||
// If we are unable to open the resource, we will create our own resource with
|
||||
// just the filename. This allows decoders that rely on other systems to fetch
|
||||
// their content to function without a custom resource provider.
|
||||
// For example, USD may use identifiers to assets that are strictly in memory
|
||||
// or that are fetched on a need-be basis via URI.
|
||||
if (!resource) {
|
||||
if (resource) {
|
||||
cleanup += [resource](){ mju_closeResource(resource); };
|
||||
} else {
|
||||
resource = (mjResource*) mju_malloc(sizeof(mjResource));
|
||||
cleanup += [resource](){ if (resource) mju_free(resource); };
|
||||
|
||||
if (resource == nullptr) {
|
||||
if (error) {
|
||||
strncpy(error, "could not allocate memory", error_sz);
|
||||
@@ -96,20 +112,19 @@ mjSpec* mj_parse(const char* filename, const char* content_type,
|
||||
std::string fullname = filename;
|
||||
std::size_t n = fullname.size();
|
||||
resource->name = (char*) mju_malloc(sizeof(char) * (n + 1));
|
||||
cleanup += [resource](){ if (resource) mju_free(resource->name); };
|
||||
|
||||
if (resource->name == nullptr) {
|
||||
if (error) {
|
||||
strncpy(error, "could not allocate memory", error_sz);
|
||||
error[error_sz - 1] = '\0';
|
||||
}
|
||||
mju_closeResource(resource);
|
||||
return nullptr;
|
||||
}
|
||||
memcpy(resource->name, fullname.c_str(), sizeof(char) * (n + 1));
|
||||
}
|
||||
|
||||
mjSpec* spec = mju_decodeResource(resource, content_type, vfs);
|
||||
mju_closeResource(resource);
|
||||
return spec;
|
||||
return mju_decodeResource(resource, content_type, vfs);
|
||||
}
|
||||
|
||||
// compile model
|
||||
|
||||
@@ -18,9 +18,12 @@
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <deque>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
const double mjEPS = 1E-14; // minimum value in various calculations
|
||||
@@ -235,6 +238,15 @@ class FilePath {
|
||||
std::string path_;
|
||||
};
|
||||
|
||||
// utility class for scoping resources to functions
|
||||
struct Cleanup {
|
||||
using Fn = std::function<void()>;
|
||||
~Cleanup() { for (auto& f : cleanup) f(); }
|
||||
void operator+=(Fn f) { cleanup.push_front(std::move(f)); }
|
||||
std::deque<Fn> cleanup;
|
||||
};
|
||||
|
||||
|
||||
// read file into memory buffer
|
||||
std::vector<uint8_t> FileToMemory(const char* filename);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user