Introduce mjpEncoder plugin architecture
Add a new mjpEncoder plugin type mirroring the existing mjpDecoder pattern. Encoders serialize an mjSpec + mjModel to an mjResource for a given format. New API functions: - mjp_registerEncoder: globally register an encoder - mjp_defaultEncoder: zero-initialize an encoder struct - mjp_findEncoder: look up an encoder by filename extension or content type The mjfEncode callback takes (mjSpec*, mjModel*, mjVFS*, mjResource*) and returns 0 on success. Writing to mjResource keeps symmetry with the decoder reading from mjResource and leaves the door open for writable resource providers. PiperOrigin-RevId: 889187898 Change-Id: I180771b2255b91dea188ac5e2cdc3a8f0fb85364
This commit is contained in:
committed by
Copybara-Service
parent
2d33b50243
commit
f5d3ce3451
@@ -16,6 +16,8 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
@@ -136,6 +138,57 @@ mjSpec* mj_parse(const char* filename, const char* content_type,
|
||||
return spec;
|
||||
}
|
||||
|
||||
// encode spec/model to file
|
||||
int mj_encode(const mjSpec* s, const mjModel* m, const char* filename,
|
||||
const char* content_type, const mjVFS* vfs, char* error,
|
||||
int error_sz) {
|
||||
const mjpEncoder* encoder = mjp_findEncoder(filename, content_type);
|
||||
if (!encoder) {
|
||||
if (error) {
|
||||
strncpy(error, "no encoder found", error_sz);
|
||||
error[error_sz - 1] = '\0';
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
mjResource resource;
|
||||
memset(&resource, 0, sizeof(resource));
|
||||
resource.name = const_cast<char*>(filename);
|
||||
|
||||
const int nbytes = encoder->encode(s, m, vfs, &resource);
|
||||
if (nbytes < 0 || !resource.data) {
|
||||
if (error) {
|
||||
strncpy(error, "encoder failed", error_sz);
|
||||
error[error_sz - 1] = '\0';
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
FILE* fp = fopen(filename, "wb");
|
||||
if (!fp) {
|
||||
std::free(resource.data);
|
||||
if (error) {
|
||||
strncpy(error, "could not open file for writing", error_sz);
|
||||
error[error_sz - 1] = '\0';
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
const std::size_t written = fwrite(resource.data, 1, nbytes, fp);
|
||||
fclose(fp);
|
||||
encoder->close_resource(&resource);
|
||||
|
||||
if (static_cast<int>(written) != nbytes) {
|
||||
if (error) {
|
||||
strncpy(error, "failed to write all bytes to file", error_sz);
|
||||
error[error_sz - 1] = '\0';
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
// compile model
|
||||
mjModel* mj_compile(mjSpec* s, const mjVFS* vfs) {
|
||||
mjCModel* modelC = static_cast<mjCModel*>(s->element);
|
||||
|
||||
Reference in New Issue
Block a user