view dmpack.c @ 96:6bf5220fa47e

Urgh .. use memset to silence some bogus GCC warnings about using potentially uninitialized values, while that will not actually be possible. In any case, it is annoying.
author Matti Hamalainen <ccr@tnsp.org>
date Tue, 02 Oct 2012 18:52:28 +0300
parents 32250b436bca
children 324374ced543 bb14d7907eb2
line wrap: on
line source

/*
 * DMLib
 * -- PACK-file handling
 * Programmed and designed by Matti 'ccr' Hamalainen
 * (C) Copyright 2011 Tecnic Software productions (TNSP)
 */
#include "dmpack.h"
#include "dmfile.h"
#include <zlib.h>


DMPackEntry *dm_pack_entry_new()
{
    return (DMPackEntry *) dmMalloc0(sizeof(DMPackEntry));
}


void dm_pack_entry_free(DMPackEntry * node)
{
    dmFree(node);
}


void dm_pack_entry_insert(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 dm_pack_entry_delete(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 *dm_pack_find(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 dm_pack_open(const char *filename, DMPackFile ** ppPack, BOOL readOnly)
{
    unsigned int i;
    DMPackFile *pack;
    DMPackFileHeader hdr;

    *ppPack = NULL;

    // Allocate packfile-structure
    pack = (DMPackFile *) dmMalloc0(sizeof(DMPackFile));
    if (pack == NULL)
        return DMERR_MALLOC;

    // Open the file
    pack->file = fopen(filename, (readOnly) ? "rb" : "r+b");
    if (pack->file == NULL)
    {
        dmFree(pack);
        return DMERR_FOPEN;
    }

    pack->filename = dm_strdup(filename);

    // Read PACK header
    fseek(pack->file, 0L, SEEK_SET);
    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_le32(pack->file, &hdr.dirOffset))
    {
        dm_pack_close(pack);
        return DMERR_FREAD;
    }

    // Check information
    if (memcmp(&hdr.ident, DPACK_IDENT, sizeof(hdr.ident)) != 0)
    {
        dm_pack_close(pack);
        return DMERR_NOTPACK;
    }

    if (hdr.version != DPACK_VERSION)
    {
        dm_pack_close(pack);
        return DMERR_VERSION;
    }

    // Read directory
    if (fseek(pack->file, hdr.dirOffset, SEEK_SET) != 0)
    {
        dm_pack_close(pack);
        return DMERR_INVALID;
    }

    for (i = 0; i < hdr.dirEntries; i++)
    {
        // Allocate and read directory entry
        DMPackEntry *entry = dm_pack_entry_new();

        if (entry == NULL)
        {
            dm_pack_close(pack);
            return DMERR_MALLOC;
        }

        if (!dm_fread_str(pack->file, (Uint8 *) &entry->filename, sizeof(entry->filename)) ||
            !dm_fread_le32(pack->file, &entry->size) ||
            !dm_fread_le32(pack->file, &entry->offset) ||
            !dm_fread_le32(pack->file, &entry->length) ||
            !dm_fread_le32(pack->file, &entry->resFlags))
        {
            *ppPack = pack;
            return DMERR_FREAD;
        }

        // Insert into list
        dm_pack_entry_insert(&pack->entries, entry);
    }

    // Set the result
    *ppPack = pack;
    return DMERR_OK;
}


/*
 * CLOSE the packfile
 */
int dm_pack_close(DMPackFile * pack)
{
    DMPackEntry *node, *next;

    if (pack == NULL)
        return DMERR_OK;

    // Write the directory
    node = pack->entries;
    while (node != NULL)
    {
        next = node->next;
        dm_pack_entry_free(node);
        node = next;
    }

    // Close the file
    if (pack->file != NULL)
    {
        fclose(pack->file);
        pack->file = NULL;
    }

    // Free structures
    dmFree(pack->filename);
    pack->filename = NULL;

    // Free packfile
    pack->entries = NULL;
    dmFree(pack);

    return DMERR_OK;
}