// 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 #include #include 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); } int32_t dvxResRemove(const char *path, const char *name) { if (!path || !name) { return -1; } long dxeSize = dvxResDxeContentSize(path); if (dxeSize < 0) { return -1; } DvxResDirEntryT *entries = NULL; uint32_t count = 0; uint8_t **data = NULL; dvxResReadExisting(path, dxeSize, &entries, &count, &data); if (!entries || count == 0) { return -1; } bool found = false; for (uint32_t i = 0; i < count; i++) { if (strcmp(entries[i].name, name) == 0) { free(data[i]); for (uint32_t j = i; j < count - 1; j++) { entries[j] = entries[j + 1]; data[j] = data[j + 1]; } count--; found = true; break; } } if (!found) { for (uint32_t i = 0; i < count; i++) { free(data[i]); } free(data); free(entries); return -1; } int32_t result; if (count == 0) { // No resources left -- truncate to DXE content only FILE *f = fopen(path, "rb"); if (!f) { free(data); free(entries); return -1; } uint8_t *dxeBuf = (uint8_t *)malloc((size_t)dxeSize); if (!dxeBuf) { fclose(f); free(data); free(entries); return -1; } if (fread(dxeBuf, 1, (size_t)dxeSize, f) != (size_t)dxeSize) { free(dxeBuf); fclose(f); free(data); free(entries); return -1; } fclose(f); f = fopen(path, "wb"); if (f) { fwrite(dxeBuf, 1, (size_t)dxeSize, f); fclose(f); result = 0; } else { result = -1; } free(dxeBuf); } else { result = dvxResWriteBlock(path, dxeSize, entries, count, data); } for (uint32_t i = 0; i < count; i++) { free(data[i]); } free(data); free(entries); return result; }