mirror of
https://github.com/libretro/beetle-pce-fast-libretro.git
synced 2024-11-30 11:30:51 +00:00
267 lines
5.2 KiB
C++
267 lines
5.2 KiB
C++
/* 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 <trio/trio.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*)MDFN_malloc(f_size, _("file read buffer"))))
|
|
goto doret;
|
|
if ((int64)::fread(f_data, 1, f_size, (FILE *)fp) != f_size)
|
|
{
|
|
ErrnoHolder ene(errno);
|
|
MDFN_PrintError(_("Error reading file: %s"), ene.StrError());
|
|
|
|
free(f_data);
|
|
goto doret;
|
|
}
|
|
|
|
ret = TRUE;
|
|
|
|
doret:
|
|
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")))
|
|
{
|
|
ErrnoHolder ene(errno);
|
|
|
|
if (ene.Errno() != ENOENT || !suppress_notfound_pe)
|
|
MDFN_PrintError(_("Error opening \"%s\": %s"), path, ene.StrError());
|
|
|
|
return 0;
|
|
}
|
|
|
|
::fseek(fp, 0, SEEK_SET);
|
|
|
|
if (!MakeMemWrapAndClose(fp))
|
|
return 0;
|
|
|
|
const char *ld = strrchr(path, '.');
|
|
f_ext = strdup(ld ? ld + 1 : "");
|
|
|
|
// FIXME: Handle extension fixing for cases where loaded filename is like "moo.moo/lalala"
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
bool MDFNFILE::Close(void)
|
|
{
|
|
if (f_ext)
|
|
{
|
|
free(f_ext);
|
|
f_ext = NULL;
|
|
}
|
|
|
|
if (f_data)
|
|
{
|
|
free(f_data);
|
|
f_data = NULL;
|
|
}
|
|
|
|
return(1);
|
|
}
|
|
|
|
uint64 MDFNFILE::fread(void *ptr, size_t element_size, size_t nmemb)
|
|
{
|
|
uint32 total = element_size * nmemb;
|
|
|
|
if (location >= f_size)
|
|
return 0;
|
|
|
|
if ((location + total) > f_size)
|
|
{
|
|
int64 ak = f_size - location;
|
|
|
|
memcpy((uint8*)ptr, f_data + location, ak);
|
|
|
|
location = f_size;
|
|
|
|
return(ak / element_size);
|
|
}
|
|
else
|
|
{
|
|
memcpy((uint8*)ptr, f_data + location, total);
|
|
|
|
location += total;
|
|
|
|
return nmemb;
|
|
}
|
|
}
|
|
|
|
int MDFNFILE::fseek(int64 offset, int whence)
|
|
{
|
|
switch(whence)
|
|
{
|
|
case SEEK_SET:
|
|
if (offset >= f_size)
|
|
return -1;
|
|
|
|
location = offset;
|
|
break;
|
|
case SEEK_CUR:
|
|
if ((offset + location) > f_size)
|
|
return -1;
|
|
|
|
location += offset;
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
static INLINE bool MDFN_DumpToFileReal(const char *filename, int compress, const std::vector<PtrLengthPair> &pearpairs)
|
|
{
|
|
FILE *fp = fopen(filename, "wb");
|
|
|
|
if (!fp)
|
|
return 0;
|
|
|
|
for(unsigned int i = 0; i < pearpairs.size(); i++)
|
|
{
|
|
const void *data = pearpairs[i].GetData();
|
|
const uint64 length = pearpairs[i].GetLength();
|
|
|
|
if (fwrite(data, 1, length, fp) != length)
|
|
{
|
|
fclose(fp);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if (fclose(fp) == EOF)
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
bool MDFN_DumpToFile(const char *filename, int compress, const std::vector<PtrLengthPair> &pearpairs)
|
|
{
|
|
return (MDFN_DumpToFileReal(filename, compress, pearpairs));
|
|
}
|
|
|
|
bool MDFN_DumpToFile(const char *filename, int compress, const void *data, uint64 length)
|
|
{
|
|
std::vector<PtrLengthPair> tmp_pairs;
|
|
tmp_pairs.push_back(PtrLengthPair(data, length));
|
|
return (MDFN_DumpToFileReal(filename, compress, tmp_pairs));
|
|
}
|