Mercurial > hg > dmlib
view dmpackutil.c @ 526:f7df57cafdd9
Add support for Interpaint (unpacked) and Doodle (unpacked) hires formats.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Thu, 22 Nov 2012 01:07:45 +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; }