view dmpack.c @ 0:32250b436bca

Initial re-import.
author Matti Hamalainen <ccr@tnsp.org>
date Fri, 28 Sep 2012 01:54:23 +0300
parents
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;
}