/*
 *
 * UNICON - The Console Chinese & I18N
 * Copyright (c) 1999-2000
 *
 * This file is part of UNICON, a console Chinese & I18N
 *
 * 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.
 *
 * See the file COPYING directory of this archive
 * Author: see CREDITS
 */

#include <iostream.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>

#include <TLC_MemFile.hpp>

TLC_CMemFile::TLC_CMemFile (u_long max0)
{
    buf = (char *) malloc (max0);
    if (buf == NULL)
    {
        cout << "No Enough Memory to run in TLC_CMemFile ()\n";
        exit (-1);
    }
    bAllocate = true;
    max = max0;
    len = 0;
    pos = 0;
}

TLC_CMemFile::TLC_CMemFile (char *buf0, u_long len0, u_long max0)
{
   bAllocate = false;
   buf = buf0;
   max = max0;
   len = len0;
   pos = 0;
}

TLC_CMemFile::~TLC_CMemFile ()
{
   if (bAllocate == true)
       free (buf);
}

void TLC_CMemFile::SetBufLen (int len0)
{
    assert (len0 < max);
    len = len0;
}

int TLC_CMemFile::fseek (long offset, int whence)
{
    long t = pos;
    switch (whence)
    {
        case SEEK_SET:
             t = offset;
             break;
        case SEEK_END:
             t = len - offset;
             break;
        case SEEK_CUR:
             t = pos + offset;
             break;
        default:
            assert (false);
            break;
    }
    if (t > len || t < 0)
        return -1;
    pos = t;
    return 0;
}

long TLC_CMemFile::ftell ()
{
    return pos;
}

size_t TLC_CMemFile::fread (void *ptr, size_t size, size_t nmemb)
{
    long t = size * nmemb;
    if (t + pos > len)
        nmemb = (len - pos)/size; 
    memcpy (ptr, &buf[pos], size * nmemb);
    pos += (size * nmemb);
    return nmemb;
}

size_t  TLC_CMemFile::fwrite (void  *ptr,  size_t  size, size_t nmemb)
{
    long t = size * nmemb;
    if (t + pos > max)
        nmemb = (max - pos)/size; 
    memcpy (&buf[pos], ptr, size * nmemb);
    pos += (size * nmemb);
    if (pos > len)
        len = pos;
    return nmemb;
}

void TLC_CMemFile::rewind ()
{
    pos = 0;
}

char *TLC_CMemFile::pGetBuf ()
{
    return buf;
}
char *TLC_CMemFile::pGetCurrentPos ()
{
    return &buf[pos];
}

u_long TLC_CMemFile::GetBufLen ()
{
    return len;
}

u_long TLC_CMemFile::GetMax ()
{
    return max;
}
/* operator overload */
TLC_CMemFile & operator << (TLC_CMemFile &in, long b)
{
    in.fwrite ((void *)&b, sizeof (long), 1);
    return in;
}

TLC_CMemFile & operator << (TLC_CMemFile &in, short b)
{
    in.fwrite (&b, sizeof (short), 1);
    return in;
}

TLC_CMemFile & operator << (TLC_CMemFile &in, char b)
{
    in.fwrite (&b, sizeof (char), 1);
    return in;
}

TLC_CMemFile & operator << (TLC_CMemFile &in, PSTR str)
{
    char *p = (char *) str;
    size_t len = strlen (p);
    in.fwrite (p, 1, len + 1); 
    return in;
}

TLC_CMemFile & operator >> (TLC_CMemFile &in, long &b)
{
    in.fread ((void *)&b, sizeof (long), 1);
    return in;
}

TLC_CMemFile & operator >> (TLC_CMemFile &in, short &b)
{
    in.fread (&b, sizeof (short), 1);
    return in;
}

TLC_CMemFile & operator >> (TLC_CMemFile &in, char &b)
{
   in.fread (&b, sizeof (char), 1);
   return in;
}

TLC_CMemFile & operator >> (TLC_CMemFile &in, PSTR &str)
{
   char ch, *p = (char *) str;
   do
   {
       if (in.fread (&ch, sizeof (char), 1) != 1)
           break;
       *p++ = ch;
   }
   while (ch != '\0');
   return in;
}

#ifdef TEST
int main ()
{
    char buf[256];
    TLC_CMemFile  MyMemFile (buf, 0, sizeof (buf));
    char *test = "12345";
    char test2[256];

    MyMemFile.fwrite (test, 1, strlen (test) + 1);
    printf ("fwrite (%s)\n", test);
    MyMemFile.rewind ();
    MyMemFile. fread (test2, 1, strlen (test) + 1);
    printf ("fread (%s)\n", test2); 

    long a, b = 12345;
    MyMemFile.rewind ();
    MyMemFile << b;
    MyMemFile.rewind ();
    MyMemFile >> a;
    printf ("%ld\n", a);

    PSTR c = "54321";
    PSTR d = (PSTR) test2;
    MyMemFile.rewind ();
    MyMemFile << "54321";
    MyMemFile.rewind ();
    MyMemFile >> d; 
    printf ("%s", test2);

}
#endif

