DVX_GUI/core/dvxResource.c

146 lines
2.8 KiB
C

// dvxResource.c -- DVX resource runtime API
//
// Reads the resource block appended to DXE3 files. The resource
// block is located by reading the footer at the end of the file.
#include "dvxRes.h"
#include "../tools/dvxResWrite.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
DvxResHandleT *dvxResOpen(const char *path) {
if (!path) {
return NULL;
}
FILE *f = fopen(path, "rb");
if (!f) {
return NULL;
}
// Read footer from end of file
if (fseek(f, -(int32_t)sizeof(DvxResFooterT), SEEK_END) != 0) {
fclose(f);
return NULL;
}
DvxResFooterT footer;
if (fread(&footer, sizeof(footer), 1, f) != 1) {
fclose(f);
return NULL;
}
if (footer.magic != DVX_RES_MAGIC || footer.entryCount == 0) {
fclose(f);
return NULL;
}
// Read directory
if (fseek(f, footer.dirOffset, SEEK_SET) != 0) {
fclose(f);
return NULL;
}
DvxResDirEntryT *entries = (DvxResDirEntryT *)malloc(footer.entryCount * sizeof(DvxResDirEntryT));
if (!entries) {
fclose(f);
return NULL;
}
if (fread(entries, sizeof(DvxResDirEntryT), footer.entryCount, f) != footer.entryCount) {
free(entries);
fclose(f);
return NULL;
}
fclose(f);
DvxResHandleT *h = (DvxResHandleT *)malloc(sizeof(DvxResHandleT));
if (!h) {
free(entries);
return NULL;
}
strncpy(h->path, path, sizeof(h->path) - 1);
h->path[sizeof(h->path) - 1] = '\0';
h->entries = entries;
h->entryCount = footer.entryCount;
return h;
}
const DvxResDirEntryT *dvxResFind(DvxResHandleT *h, const char *name) {
if (!h || !name) {
return NULL;
}
for (uint32_t i = 0; i < h->entryCount; i++) {
if (strcmp(h->entries[i].name, name) == 0) {
return &h->entries[i];
}
}
return NULL;
}
void *dvxResRead(DvxResHandleT *h, const char *name, uint32_t *outSize) {
const DvxResDirEntryT *entry = dvxResFind(h, name);
if (!entry) {
return NULL;
}
FILE *f = fopen(h->path, "rb");
if (!f) {
return NULL;
}
if (fseek(f, entry->offset, SEEK_SET) != 0) {
fclose(f);
return NULL;
}
void *buf = malloc(entry->size);
if (!buf) {
fclose(f);
return NULL;
}
if (fread(buf, 1, entry->size, f) != entry->size) {
free(buf);
fclose(f);
return NULL;
}
fclose(f);
if (outSize) {
*outSize = entry->size;
}
return buf;
}
void dvxResClose(DvxResHandleT *h) {
if (h) {
free(h->entries);
free(h);
}
}
int32_t dvxResAppend(const char *path, const char *name, uint32_t type, const void *data, uint32_t dataSize) {
return dvxResAppendEntry(path, name, type, data, dataSize);
}