Don't read from file until mju_readResource is called.

PiperOrigin-RevId: 615434757
Change-Id: I96a1e77f74203e91bc62dc24ac9225810fcacb20
This commit is contained in:
Kyle Bayes
2024-03-13 08:54:46 -07:00
committed by Copybara-Service
parent 40baa51072
commit 0d16587135
+46 -21
View File
@@ -35,12 +35,17 @@
#include "engine/engine_plugin.h"
#include "engine/engine_util_errmem.h"
// internal helper for mju_fileToMemory (closes fp automatically)
static void* _fileToMemory(FILE* fp, const char* filename, size_t* filesize);
// file buffer used internally for the OS filesystem
typedef struct {
FILE* fp; // file handle
int is_read; // set to nonzero if buffer was read into
uint8_t* buffer; // raw bytes from file
size_t nbuffer; // size of buffer in bytes
time_t mtime; // last modified time
} file_buffer;
} file_spec;
// open the given resource; if the name doesn't have a prefix matching with a
// resource provider, then the OS filesystem is used
@@ -89,10 +94,13 @@ mjResource* mju_openResource(const char* name, char* error, size_t error_sz) {
// lastly fallback to OS filesystem
resource->provider = NULL;
resource->data = mju_malloc(sizeof(file_buffer));
file_buffer* fb = (file_buffer*) resource->data;
fb->buffer = mju_fileToMemory(name, &(fb->nbuffer));
if (fb->buffer == NULL) {
resource->data = mju_malloc(sizeof(file_spec));
file_spec* spec = (file_spec*) resource->data;
spec->is_read = 0;
spec->buffer = NULL;
spec->nbuffer = 0;
spec->fp = fopen(name, "rb");
if (!spec->fp) {
if (error) {
snprintf(error, error_sz,
"resource not found via provider or OS filesystem: '%s'", name);
@@ -102,12 +110,13 @@ mjResource* mju_openResource(const char* name, char* error, size_t error_sz) {
}
struct stat file_stat;
if (stat(name, &file_stat) == 0) {
memcpy(&fb->mtime, &file_stat.st_mtime, sizeof(time_t));
memcpy(&spec->mtime, &file_stat.st_mtime, sizeof(time_t));
} else {
memset(&fb->mtime, 0, sizeof(time_t));
memset(&spec->mtime, 0, sizeof(time_t));
resource->timestamp[0] = '\0';
}
strftime(resource->timestamp, 512, "%Y-%m-%d-%H:%M:%S", localtime(&(fb->mtime)));
strftime(resource->timestamp, 512, "%Y-%m-%d-%H:%M:%S",
localtime(&(spec->mtime)));
return resource;
}
@@ -124,10 +133,10 @@ void mju_closeResource(mjResource* resource) {
resource->provider->close(resource);
} else {
// clear OS filesystem if present
file_buffer* fb = (file_buffer*) resource->data;
if (fb) {
if (fb->buffer) mju_free(fb->buffer);
mju_free(fb);
file_spec* spec = (file_spec*) resource->data;
if (spec) {
if (spec->buffer) mju_free(spec->buffer);
mju_free(spec);
}
}
@@ -151,9 +160,19 @@ int mju_readResource(mjResource* resource, const void** buffer) {
// if provider is NULL, then OS filesystem is used
const file_buffer* fb = (file_buffer*) resource->data;
*buffer = fb->buffer;
return fb->nbuffer;
file_spec* spec = (file_spec*) resource->data;
if (!spec->fp && !spec->is_read) {
mjERROR("internal error FILE pointer undefined"); // should not occur
}
// only read once from file
if (!spec->is_read) {
spec->buffer = _fileToMemory(spec->fp, resource->name, &(spec->nbuffer));
spec->fp = NULL; // closed by _fileToMemory
spec->is_read = 1;
}
*buffer = spec->buffer;
return spec->nbuffer;
}
@@ -181,11 +200,11 @@ void mju_getResourceDir(mjResource* resource, const char** dir, int* ndir) {
// modified callback for OS filesystem
static int mju_isModifiedFile(const char* name, const file_buffer* fb) {
if (fb != NULL) {
static int mju_isModifiedFile(const char* name, const file_spec* spec) {
if (spec != NULL) {
struct stat file_stat;
if (stat(name, &file_stat) == 0) {
return difftime(fb->mtime, file_stat.st_mtime) < 0;
return difftime(spec->mtime, file_stat.st_mtime) < 0;
}
}
return 1; // modified (default)
@@ -205,7 +224,7 @@ int mju_isModifiedResource(const mjResource* resource, const char* timestamp) {
return 1; // default (modified)
}
return mju_isModifiedFile(resource->name, (file_buffer*) resource->data);
return mju_isModifiedFile(resource->name, (file_spec*) resource->data);
}
@@ -230,13 +249,19 @@ int mju_dirnamelen(const char* path) {
// read file into memory buffer (allocated here with mju_malloc)
void* mju_fileToMemory(const char* filename, size_t* filesize) {
// open file
*filesize = 0;
FILE* fp = fopen(filename, "rb");
if (!fp) {
return NULL;
}
return _fileToMemory(fp, filename, filesize);
}
// internal helper for mju_fileToMemory (closes fp automatically)
static void* _fileToMemory(FILE* fp, const char* filename, size_t* filesize) {
// open file
*filesize = 0;
// find size
if (fseek(fp, 0, SEEK_END) != 0) {
fclose(fp);