Don't read from file until mju_readResource is called.
PiperOrigin-RevId: 615434757 Change-Id: I96a1e77f74203e91bc62dc24ac9225810fcacb20
This commit is contained in:
committed by
Copybara-Service
parent
40baa51072
commit
0d16587135
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user