Mercurial > hg > dmlib
view dmpackutil.c @ 510:43ea59887c69
Start work on making C64 formats encoding possible by changing DMDecodeOps
to DMEncDecOps and adding fields and op enums for custom encode functions, renaming,
etc. Split generic op sanity checking into a separate function in
preparation for its use in generic encoding function.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Mon, 19 Nov 2012 15:06:01 +0200 |
parents | 32250b436bca |
children | 09528946f92b bb14d7907eb2 |
line wrap: on
line source
/* * DMLib * -- PACK-file additional utility routines * Programmed and designed by Matti 'ccr' Hamalainen * (C) Copyright 2011 Tecnic Software productions (TNSP) */ #include "dmpackutil.h" #include <zlib.h> #include "dmfile.h" DMPackEntry *dm_pack_entry_copy(const DMPackEntry *src) { DMPackEntry *node = dm_pack_entry_new(); if (node == NULL) return NULL; strncpy(node->filename, src->filename, sizeof(node->filename)); node->filename[sizeof(node->filename) - 1] = 0; node->size = src->size; node->offset = src->offset; node->length = src->length; node->resFlags = src->resFlags; return node; } /* * CLOSE/WRITE the packfile */ int dm_pack_write(DMPackFile * pack) { DMPackEntry *node; DMPackFileHeader hdr; if (pack == NULL) return DMERR_OK; if (pack->file == NULL) return DMERR_FOPEN; // Compute directory offset and number of entries memcpy(&hdr.ident, DPACK_IDENT, sizeof(hdr.ident)); hdr.version = DPACK_VERSION; hdr.dirEntries = 0; hdr.dirOffset = sizeof(hdr.ident) + sizeof(hdr.version) + sizeof(hdr.dirEntries) + sizeof(hdr.dirOffset); node = pack->entries; while (node != NULL) { hdr.dirEntries++; hdr.dirOffset += node->length; node = node->next; } // Write PACK header if (fseek(pack->file, 0L, SEEK_SET) != 0) return -4; dm_fwrite_str(pack->file, (Uint8 *) & hdr.ident, sizeof(hdr.ident)); dm_fwrite_le16(pack->file, hdr.version); dm_fwrite_le32(pack->file, hdr.dirEntries); dm_fwrite_le32(pack->file, hdr.dirOffset); // Write the directory if (fseek(pack->file, hdr.dirOffset, SEEK_SET) != 0) return -5; node = pack->entries; while (node != NULL) { // Write one entry dm_fwrite_str(pack->file, node->filename, sizeof(node->filename)); dm_fwrite_le32(pack->file, node->size); dm_fwrite_le32(pack->file, node->offset); dm_fwrite_le32(pack->file, node->length); dm_fwrite_le32(pack->file, node->resFlags); node = node->next; } return DMERR_OK; } /* * CREATE a packfile, for writing */ int dm_pack_create(const char *filename, DMPackFile ** pack) { // Allocate packfile-structure *pack = (DMPackFile *) dmCalloc(1, sizeof(DMPackFile)); if (*pack == NULL) return DMERR_MALLOC; // Open the file (*pack)->file = fopen(filename, "wb"); if ((*pack)->file == NULL) { dmFree(*pack); return DMERR_FOPEN; } (*pack)->filename = dm_strdup(filename); // Set the result return DMERR_OK; } /* * ADD a file into the PACK */ int dm_pack_add_file(DMPackFile * pack, const char *filename, BOOL doCompress, int resFlags, DMPackEntry ** ppEntry) { z_stream compStream; off_t startOffs; unsigned int compSize; FILE *inFile; Uint8 *inBuffer, *outBuffer; DMPackEntry entry, *node; int result; *ppEntry = NULL; if (pack == NULL) return DMERR_OK; if (pack->file == NULL) return DMERR_FOPEN; // Compute starting offset startOffs = sizeof(DMPackFileHeader); node = pack->entries; while (node != NULL) { startOffs += node->length; node = node->next; } // Seek to the position if (fseek(pack->file, startOffs, SEEK_SET) != 0) return DMERR_INVALID; // Read file data if ((inFile = fopen(filename, "rb")) == NULL) return -1; // Allocate temporary buffer inBuffer = (Uint8 *) dmMalloc(DPACK_TMPSIZE); if (!inBuffer) { fclose(inFile); return DMERR_MALLOC; } outBuffer = (Uint8 *) dmMalloc(DPACK_TMPSIZE); if (!outBuffer) { dmFree(inBuffer); fclose(inFile); return DMERR_MALLOC; } // Read (and possibly compress) the data compSize = 0; compStream.zalloc = (alloc_func) Z_NULL; compStream.zfree = (free_func) Z_NULL; compStream.opaque = (voidpf) Z_NULL; result = deflateInit(&compStream, (doCompress) ? Z_DEFAULT_COMPRESSION : 0); if (result != Z_OK) { dmFree(inBuffer); dmFree(outBuffer); fclose(inFile); return DMERR_COMPRESSION; } // Initialize compression streams result = Z_OK; while (!feof(inFile) && result == Z_OK) { compStream.avail_in = fread(inBuffer, sizeof(Uint8), DPACK_TMPSIZE, inFile); compStream.next_in = inBuffer; compStream.next_out = outBuffer; compStream.avail_out = DPACK_TMPSIZE; compStream.total_out = 0; result = deflate(&compStream, Z_FULL_FLUSH); if (result == Z_OK && compStream.total_out > 0) { compSize += compStream.total_out; fwrite(outBuffer, sizeof(Uint8), compStream.total_out, pack->file); } } // Create directory entry strncpy(entry.filename, filename, sizeof(entry.filename)); entry.filename[sizeof(entry.filename) - 1] = 0; entry.size = compStream.total_in; entry.offset = startOffs; entry.length = compSize; entry.resFlags = resFlags; // Cleanup deflateEnd(&compStream); dmFree(inBuffer); dmFree(outBuffer); fclose(inFile); // Add directory entry *ppEntry = dm_pack_entry_copy(&entry); if (*ppEntry == NULL) return DMERR_MALLOC; dm_pack_entry_insert(&pack->entries, *ppEntry); return DMERR_OK; } /* * EXTRACT a file from the PACK */ int dm_pack_extract_file(DMPackFile *pack, DMPackEntry * entry) { z_stream compStream; FILE *outFile; Uint8 *inBuffer, *outBuffer; size_t inDataLeft; int ret; if (pack == NULL) return DMERR_OK; if (pack->file == NULL) return DMERR_FOPEN; // Seek to the position if (fseek(pack->file, entry->offset, SEEK_SET) != 0) return DMERR_INVALID; // Open destination file if ((outFile = fopen(entry->filename, "wb")) == NULL) return -1; // Allocate temporary buffer if ((inBuffer = (Uint8 *) dmMalloc(DPACK_TMPSIZE)) == NULL) { fclose(outFile); return DMERR_MALLOC; } if ((outBuffer = (Uint8 *) dmMalloc(DPACK_TMPSIZE)) == NULL) { dmFree(inBuffer); fclose(outFile); return DMERR_MALLOC; } // Read and uncompress the data compStream.zalloc = (alloc_func) Z_NULL; compStream.zfree = (free_func) Z_NULL; compStream.opaque = (voidpf) Z_NULL; ret = inflateInit(&compStream); if (ret != Z_OK) { dmFree(inBuffer); dmFree(outBuffer); fclose(outFile); return DMERR_COMPRESSION; } // Initialize compression streams inDataLeft = entry->length; ret = Z_OK; while (inDataLeft > 0 && ret == Z_OK) { if (inDataLeft >= DPACK_TMPSIZE) compStream.avail_in = fread(inBuffer, sizeof(Uint8), DPACK_TMPSIZE, pack->file); else compStream.avail_in = fread(inBuffer, sizeof(Uint8), inDataLeft, pack->file); inDataLeft -= compStream.avail_in; compStream.next_in = inBuffer; while (compStream.avail_in > 0 && ret == Z_OK) { compStream.next_out = outBuffer; compStream.avail_out = DPACK_TMPSIZE; compStream.total_out = 0; ret = inflate(&compStream, Z_FULL_FLUSH); if (compStream.total_out > 0) { fwrite(outBuffer, sizeof(Uint8), compStream.total_out, outFile); } } } // Cleanup inflateEnd(&compStream); dmFree(inBuffer); dmFree(outBuffer); fclose(outFile); return DMERR_OK; }