// This file is a part of the xMule Project.
//
// Copyright (c) 2004 Theodore R. Smith (hopeseekr@xmule.ws / http://www.xmule.ws/)
// DSA-1024 Fingerprint: 10A0 6372 9092 85A2 BB7F 907B CB8B 654B E33B F1ED
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

#ifdef PRECOMP
#	include "xmule-headers.h"
#else
#	include "CMemFile.h"
#endif

#include "wintypes.h"                       // BYTE - audited 4 Nov 2004

CMemFile::CMemFile(unsigned int growBytes)
{
    fGrowBytes = growBytes;
    fLength = 0;
    fPosition = 0;
    fBufferSize = 0;
    fFileSize = 0;
    fBuffer = NULL;
    deleteBuffer = TRUE;
}

CMemFile::CMemFile(BYTE *buffer, unsigned int bufferSize, unsigned int growBytes)
{
    fBufferSize = bufferSize;
    fPosition = 0;
    fGrowBytes = growBytes;
    if (!growBytes) fFileSize = bufferSize;
    else fFileSize = 0;
    // uh:
    fBuffer = buffer;
    deleteBuffer = FALSE;
}

void CMemFile::Attach(BYTE *buffer, unsigned int bufferSize, unsigned int growBytes)
{
    fBufferSize = bufferSize;
    fPosition = 0;
    fGrowBytes = growBytes;
    if (!growBytes) fFileSize = bufferSize;
    else fFileSize = 0;
    // uh:
    fBuffer = buffer;
    deleteBuffer = FALSE;
}

BYTE *CMemFile::Detach()
{
    BYTE *retval = fBuffer;
    fBuffer = NULL;
    fFileSize = fBufferSize = fPosition = fFileSize = 0;
    return retval;
}

CMemFile::~CMemFile()
{
    fGrowBytes = fPosition = fBufferSize = fFileSize = 0;
    // should the buffer be free'd ?
    if (fBuffer &&deleteBuffer) free(fBuffer);
    fBuffer = NULL;
}

off_t CMemFile::Seek(off_t offset, wxSeekMode from)
{
    off_t newpos = 0;
    switch (from)
    {
    case wxFromStart:
        newpos = offset;
        break;
    case wxFromCurrent:
        newpos = fPosition + offset;
        break;
    case wxFromEnd:
        newpos = fFileSize - offset;
        break;
    default:
        return - 1;
    }
    if (newpos < 0)
    {
        return - 1;
    }
    // what if we seek over the end??
    fPosition = newpos;
    return fPosition;
}

void CMemFile::enlargeBuffer(unsigned long size)
{
    unsigned long newsize = fBufferSize;
    // hmm.. mitähän jos growbytes==0??
    while (newsize < size)
    newsize += fGrowBytes;
    if (fBuffer)
    fBuffer = (BYTE *) realloc((void *) fBuffer, newsize);
    else fBuffer = (BYTE *) malloc(newsize);
    if (fBuffer == NULL)
    {
        // jaa-a. mitähän tekis
        printf("out of memory experience\n");
        exit(1);
    }
    fBufferSize = newsize;
}

void CMemFile::SetLength(unsigned long newLen)
{
    if (newLen > fBufferSize)
    {
        // enlarge buffer
        enlargeBuffer(newLen);
    }
    if (newLen < fPosition)
    {
        fPosition = newLen;
    }
    fFileSize = newLen;
}

off_t CMemFile::Read(void *buf, off_t length)
{
    if (length == 0)
    return 0;
    // dont' read over buffer end
    if (fPosition > fFileSize)
    return 0;
    unsigned int readlen = length;
    if (length + fPosition > fFileSize)
    readlen = fFileSize - fPosition;
    memcpy(buf, fBuffer + fPosition, readlen);
    fPosition += readlen;
    return readlen;
}

size_t CMemFile::Write(const void *buf, size_t length)
{
    if (length == 0)
    return 0;
    // need more space?
    if (fPosition + length > fBufferSize)
    enlargeBuffer(fPosition + length);
    memcpy(fBuffer + fPosition, buf, length);
    fPosition += length;
    if (fPosition > fFileSize)
    fFileSize = fPosition;
    return length;
}

bool CMemFile::Close()
{
    // do-nothing :)
    return TRUE;
}

