/*
 * DMLib
 * -- Standard I/O (stdio) file write/read endianess helpers
 * Programmed and designed by Matti 'ccr' Hamalainen
 * (C) Copyright 2011 Tecnic Software productions (TNSP)
 */
#include "dmfile.h"


BOOL dm_fread_str(FILE *f, void *buf, const size_t len)
{
    return fread(buf, len, 1, f) == 1;
}


BOOL dm_fread_byte(FILE *f, Uint8 *val)
{
    int tmp = fgetc(f);
    *val = tmp;
    return tmp != EOF;
}


#define DM_DEFINE_FFUNC(xname, xtype, xmacro)         \
BOOL dm_fread_ ## xname (FILE *f, xtype *v) {         \
    xtype result;                                     \
    if (fread(&result, sizeof( xtype ), 1, f) != 1)   \
        return FALSE;                                 \
    *v = DM_ ## xmacro ## _TO_NATIVE (result);        \
    return TRUE;                                      \
}

#include "dmfiletmpl.h"


#undef DM_DEFINE_FFUNC


BOOL dm_fwrite_str(FILE *f, const void *buf, const size_t len)
{
    return fwrite(buf, len, 1, f) == 1;
}


BOOL dm_fwrite_byte(FILE *f, const Uint8 val)
{
    return fputc(val, f) == val;
}


#define DM_DEFINE_FFUNC(xname, xtype, xmacro)         \
BOOL dm_fwrite_ ## xname (FILE *f, const xtype v) {   \
    xtype result = DM_NATIVE_TO_ ## xmacro (v);       \
    if (fwrite(&result, sizeof( xtype ), 1, f) != 1)  \
        return FALSE;                                 \
    return TRUE;                                      \
}

#include "dmfiletmpl.h"

#undef DM_DEFINE_FFUNC


#define BUF_SIZE_INITIAL   (16*1024)
#define BUF_SIZE_GROW      (4*1024)

int dmReadDataFile(FILE *inFile, const char *filename, Uint8 **pbuf, size_t *pbufSize)
{
    FILE *f;
    int res = DMERR_OK;
    Uint8 *dataBuf = NULL;
    size_t readSize, dataSize, dataRead, dataPos;
    
    if (inFile != NULL)
        f = inFile;
    else
    if (filename != NULL)
    {
        if ((f = fopen(filename, "rb")) == NULL)
        {
            dmError("Could not open '%s' for reading.\n", filename);
            return DMERR_FOPEN;
        }
    }
    else
    {
        dmError("NULL filename and stream pointers.\n");
        return DMERR_NULLPTR;
    }

    // Allocate initial data buffer
    readSize = dataSize = BUF_SIZE_INITIAL;
    if ((dataBuf = dmMalloc(dataSize)) == NULL)
    {
        dmError("Error allocating memory for data, %d bytes.\n", dataSize);
        res = DMERR_MALLOC;
        goto error;
    }

    dataPos = 0;
    dataRead = 0;

    while (!feof(f) && !ferror(f))
    {
        size_t read = fread(dataBuf + dataPos, 1, readSize, f);
        dataPos += read;
        dataRead += read;

        if (dataRead >= dataSize)
        {
            readSize = BUF_SIZE_GROW;
            dataSize += BUF_SIZE_GROW;
            if ((dataBuf = dmRealloc(dataBuf, dataSize)) == NULL)
            {
                dmError("Error reallocating memory for data, %d bytes.\n", dataSize);
                res = DMERR_MALLOC;
                goto error;
            }
        }
        else
            break;
    }

    *pbufSize = dataRead;
    *pbuf = dataBuf;

error:
    if (f != inFile)
        fclose(f);
    
    return res;
}
