Mercurial > hg > dmlib
view src/dmpack.c @ 2322:5abb81daadd5
Rename DMC64EncDecOp::offs2 to blkoffs.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Tue, 03 Sep 2019 10:41:21 +0300 |
parents | 9aa51ac4e502 |
children | 69a5af2eb1ea |
line wrap: on
line source
/* * DMLib * -- PACK-file handling * Programmed and designed by Matti 'ccr' Hamalainen * (C) Copyright 2011-2015 Tecnic Software productions (TNSP) */ #include "dmpack.h" #include "dmfile.h" DMPackEntry *dmPackEntryNew() { return (DMPackEntry *) dmMalloc0(sizeof(DMPackEntry)); } void dmPackEntryFree(DMPackEntry * node) { dmFree(node); } void dmPackEntryInsert(DMPackEntry ** packDir, DMPackEntry * node) { if (*packDir != NULL) { node->prev = (*packDir)->prev; (*packDir)->prev->next = node; (*packDir)->prev = node; } else { *packDir = node->prev = node; } node->next = NULL; } void dmPackEntryDelete(DMPackEntry ** packDir, DMPackEntry * node) { if (node->prev) node->prev->next = node->next; if (node->next) node->next->prev = node->prev; else (*packDir)->prev = node->prev; node->prev = node->next = NULL; } DMPackEntry *dmPackFind(DMPackEntry *list, const char *filename) { DMPackEntry *node; for (node = list; node != NULL; node = node->next) { if (strcmp(node->filename, filename) == 0) return node; } return NULL; } /* * OPEN a packfile */ int dmPackOpen(const char *filename, DMPackFile ** ppPack, BOOL readOnly) { unsigned int i; DMPackFile *pack = NULL; DMPackFileHeader hdr; int ret = DMERR_OK; // Allocate packfile-structure if ((pack = dmMalloc0(sizeof(DMPackFile))) == NULL) { ret = dmErrorDBG(DMERR_MALLOC, "Failed to allocate memory for PACK file structure '%s'.\n", filename); goto out; } // Open the file if ((pack->file = fopen(filename, readOnly ? "rb" : "r+b")) == NULL) { ret = dmError(dmGetErrno(), "Failed to open PACK file '%s'.\n", filename); goto out; } pack->filename = dm_strdup(filename); // Read PACK header if (fseeko(pack->file, 0L, SEEK_SET) != 0) { ret = dmErrorDBG(dmGetErrno(), "Failed to seek to file start '%s'.\n", filename); goto out; } if (!dm_fread_str(pack->file, (Uint8 *) &hdr.ident, sizeof(hdr.ident)) || !dm_fread_le16(pack->file, &hdr.version) || !dm_fread_le32(pack->file, &hdr.dirEntries) || !dm_fread_le64(pack->file, &hdr.dirOffset)) { ret = dmErrorDBG(DMERR_FREAD, "Error reading PACK file header data.\n"); goto out; } // Check information if (memcmp(&hdr.ident, DPACK_IDENT, sizeof(hdr.ident)) != 0) { ret = DMERR_NOTPACK; goto out; } if (hdr.version != DPACK_VERSION) { ret = DMERR_PACK_VERSION; goto out; } // Read directory if (hdr.dirOffset < sizeof(hdr) || fseeko(pack->file, hdr.dirOffset, SEEK_SET) != 0) { ret = dmErrorDBG(DMERR_INVALID, "Error seeking to PACK file '%s' directory offset.\n", filename); goto out; } for (i = 0; i < hdr.dirEntries; i++) { // Allocate and read directory entry DMPackEntry *entry; if ((entry = dmPackEntryNew()) == NULL) { ret = DMERR_MALLOC; goto out; } if (!dm_fread_str(pack->file, (Uint8 *) &entry->filename, DMRES_NAME_LEN) || !dm_fread_le64(pack->file, &entry->offset) || !dm_fread_le32(pack->file, &entry->length) || !dm_fread_le32(pack->file, &entry->size) || !dm_fread_le32(pack->file, &entry->flags)) { ret = DMERR_FREAD; goto out; } // Ensure that the filename ends in NUL entry->filename[DMRES_NAME_LEN] = 0; // Validate if (entry->size == 0 || entry->length == 0 || entry->length > hdr.dirOffset || entry->offset > hdr.dirOffset || strlen(entry->filename) == 0) { ret = dmErrorDBG(DMERR_INVALID, "Invalid PACK entry #%d '%s'\n", i, entry->filename); goto out; } // Insert into list dmPackEntryInsert(&pack->entries, entry); } out: if (ret != DMERR_OK) { dmPackClose(pack); pack = NULL; } *ppPack = pack; return ret; } /* * CLOSE the packfile */ int dmPackClose(DMPackFile * pack) { DMPackEntry *node; if (pack == NULL) return DMERR_OK; // Write the directory node = pack->entries; while (node != NULL) { DMPackEntry *next = node->next; dmPackEntryFree(node); node = next; } // Close the file if (pack->file != NULL) fclose(pack->file); // Free structures dmFree(pack->filename); // Free packfile dmMemset(pack, 0, sizeof(DMPackFile)); dmFree(pack); return DMERR_OK; }