/* Mednafen - Multi-system Emulator
 *
 * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "mednafen.h"
#include <stdarg.h>
#include <string.h>
#include <errno.h>

#include "file.h"
#include "general.h"

bool MDFNFILE::ApplyIPS(void *unused)
{
   (void)unused;

   return 1;
}

// This function should ALWAYS close the system file "descriptor"(gzip library, zip library, or FILE *) it's given,
// even if it errors out.
bool MDFNFILE::MakeMemWrapAndClose(void *fp)
{
   bool ret = FALSE;

   location = 0;

   ::fseek((FILE *)fp, 0, SEEK_END);
   f_size = ::ftell((FILE *)fp);
   ::fseek((FILE *)fp, 0, SEEK_SET);

   if (!(f_data = (uint8*)malloc(f_size)))
      goto fail;
   ::fread(f_data, 1, f_size, (FILE *)fp);

   ret = TRUE;
fail:
   fclose((FILE*)fp);
   return ret;
}

MDFNFILE::MDFNFILE()
{
   f_data = NULL;
   f_size = 0;
   f_ext = NULL;

   location = 0;
}

MDFNFILE::MDFNFILE(const char *path, const void *known_ext, const char *purpose)
{
   (void)known_ext;
   if (!Open(path, known_ext, purpose, false))
      throw(MDFN_Error(0, "TODO ERROR"));
}


MDFNFILE::~MDFNFILE()
{
   Close();
}


bool MDFNFILE::Open(const char *path, const void *known_ext, const char *purpose, const bool suppress_notfound_pe)
{
   FILE *fp;
   (void)known_ext;

   if (!(fp = fopen(path, "rb")))
      return FALSE;

   ::fseek(fp, 0, SEEK_SET);

   if (!MakeMemWrapAndClose(fp))
      return FALSE;

   const char *ld = (const char*)strrchr(path, '.');
   f_ext = strdup(ld ? ld + 1 : "");

   return(TRUE);
}

bool MDFNFILE::Close(void)
{
   if (f_ext)
      free(f_ext);
   f_ext = 0;

   if (f_data)
      free(f_data);
   f_data = 0;

   return(1);
}

uint64 MDFNFILE::fread(void *ptr, size_t element_size, size_t nmemb)
{
   int64 avail = f_size - location;
   if (nmemb > avail)
      nmemb = avail;

   memcpy((uint8*)ptr, f_data + location, nmemb);
   location += nmemb;
   return nmemb;
}

int MDFNFILE::fseek(int64 offset, int whence)
{
   size_t ptr;

   switch(whence)
   {
      case SEEK_SET:
         ptr = offset;
         break;
      case SEEK_CUR:
         ptr = location + offset;
         break;
      case SEEK_END:
         ptr = f_size + offset;
         break;
   }    

   if (ptr <= f_size)
   {
      location = ptr;
      return 0;
   }

   return -1;
}

int MDFNFILE::read16le(uint16 *val)
{
   if ((location + 2) > f_size)
      return 0;

   *val = MDFN_de16lsb(f_data + location);

   location += 2;

   return 1;
}

int MDFNFILE::read32le(uint32 *val)
{
   if ((location + 4) > f_size)
      return 0;

   *val = MDFN_de32lsb(f_data + location);

   location += 4;

   return 1;
}

char *MDFNFILE::fgets(char *s, int buffer_size)
{
   int pos = 0;

   if (!buffer_size)
      return(NULL);

   if (location >= buffer_size)
      return(NULL);

   while(pos < (buffer_size - 1) && location < buffer_size)
   {
      int v = f_data[location];
      s[pos] = v;
      location++;
      pos++;
      if (v == '\n')
         break;
   }

   if (buffer_size)
      s[pos] = 0;

   return s;
}
