re3/src/core/FileMgr.cpp

314 lines
5.1 KiB
C++
Raw Normal View History

2019-05-24 17:58:32 +00:00
#define _CRT_SECURE_NO_WARNINGS
#include <fcntl.h>
2020-05-11 02:55:57 +00:00
#ifdef _WIN32
2019-05-24 17:58:32 +00:00
#include <direct.h>
2020-05-11 02:55:57 +00:00
#endif
2019-05-24 17:58:32 +00:00
#include "common.h"
2020-07-26 17:59:58 +00:00
#include "crossplatform.h"
2020-04-17 13:31:11 +00:00
2019-05-24 17:58:32 +00:00
#include "FileMgr.h"
const char *_psGetUserFilesFolder();
2019-05-24 17:58:32 +00:00
/*
* Windows FILE is BROKEN for GTA.
*
* We need to support mapping between LF and CRLF for text files
* but we do NOT want to end the file at the first sight of a SUB character.
* So here is a simple implementation of a FILE interface that works like GTA expects.
*/
struct myFILE
{
bool isText;
FILE *file;
};
#define NUMFILES 20
static myFILE myfiles[NUMFILES];
2020-05-11 02:55:57 +00:00
#if !defined(_WIN32)
#include <dirent.h>
#include <errno.h>
#include <unistd.h>
#define _getcwd getcwd
// Case-insensitivity on linux (from https://github.com/OneSadCookie/fcaseopen)
void mychdir(char const *path)
{
2020-07-26 17:59:58 +00:00
char* r = casepath(path, false);
if (r) {
2020-05-11 02:55:57 +00:00
chdir(r);
2020-07-26 17:59:58 +00:00
free(r);
} else {
2020-05-11 02:55:57 +00:00
errno = ENOENT;
}
}
#else
#define mychdir chdir
#endif
2019-05-24 17:58:32 +00:00
/* Force file to open as binary but remember if it was text mode */
static int
myfopen(const char *filename, const char *mode)
{
int fd;
char realmode[10], *p;
for(fd = 1; fd < NUMFILES; fd++)
if(myfiles[fd].file == nil)
goto found;
return 0; // no free fd
found:
myfiles[fd].isText = strchr(mode, 'b') == nil;
p = realmode;
while(*mode)
if(*mode != 't' && *mode != 'b')
*p++ = *mode++;
else
mode++;
*p++ = 'b';
*p = '\0';
2020-05-11 02:55:57 +00:00
2020-07-26 17:59:58 +00:00
myfiles[fd].file = fcaseopen(filename, realmode);
2019-05-24 17:58:32 +00:00
if(myfiles[fd].file == nil)
return 0;
return fd;
}
static int
2019-05-24 17:58:32 +00:00
myfclose(int fd)
{
int ret;
2019-05-24 17:58:32 +00:00
assert(fd < NUMFILES);
if(myfiles[fd].file){
ret = fclose(myfiles[fd].file);
2019-05-24 17:58:32 +00:00
myfiles[fd].file = nil;
return ret;
2019-05-24 17:58:32 +00:00
}
return EOF;
2019-05-24 17:58:32 +00:00
}
static int
myfgetc(int fd)
{
int c;
c = fgetc(myfiles[fd].file);
if(myfiles[fd].isText && c == 015){
/* translate CRLF to LF */
c = fgetc(myfiles[fd].file);
if(c == 012)
return c;
ungetc(c, myfiles[fd].file);
return 015;
}
return c;
}
static int
myfputc(int c, int fd)
{
/* translate LF to CRLF */
if(myfiles[fd].isText && c == 012)
fputc(015, myfiles[fd].file);
return fputc(c, myfiles[fd].file);
}
static char*
myfgets(char *buf, int len, int fd)
{
int c;
char *p;
p = buf;
len--; // NUL byte
while(len--){
c = myfgetc(fd);
if(c == EOF){
if(p == buf)
return nil;
break;
}
*p++ = c;
if(c == '\n')
break;
}
*p = '\0';
return buf;
}
2020-07-22 11:56:28 +00:00
static size_t
2019-05-24 17:58:32 +00:00
myfread(void *buf, size_t elt, size_t n, int fd)
{
if(myfiles[fd].isText){
unsigned char *p;
2019-05-24 17:58:32 +00:00
size_t i;
int c;
n *= elt;
p = (unsigned char*)buf;
2019-05-24 17:58:32 +00:00
for(i = 0; i < n; i++){
c = myfgetc(fd);
if(c == EOF)
break;
*p++ = (unsigned char)c;
2019-05-24 17:58:32 +00:00
}
return i / elt;
}
return fread(buf, elt, n, myfiles[fd].file);
}
2020-07-22 11:56:28 +00:00
static size_t
2019-05-24 17:58:32 +00:00
myfwrite(void *buf, size_t elt, size_t n, int fd)
{
if(myfiles[fd].isText){
unsigned char *p;
2019-05-24 17:58:32 +00:00
size_t i;
int c;
n *= elt;
p = (unsigned char*)buf;
2019-05-24 17:58:32 +00:00
for(i = 0; i < n; i++){
c = *p++;
myfputc(c, fd);
if(feof(myfiles[fd].file)) // is this right?
break;
}
return i / elt;
}
return fwrite(buf, elt, n, myfiles[fd].file);
}
static int
myfseek(int fd, long offset, int whence)
{
return fseek(myfiles[fd].file, offset, whence);
}
static int
myfeof(int fd)
{
2019-06-13 09:57:43 +00:00
return feof(myfiles[fd].file);
// return ferror(myfiles[fd].file);
2019-05-24 17:58:32 +00:00
}
2020-04-17 05:54:14 +00:00
char CFileMgr::ms_rootDirName[128] = {'\0'};
char CFileMgr::ms_dirName[128];
2019-05-24 17:58:32 +00:00
void
CFileMgr::Initialise(void)
{
_getcwd(ms_rootDirName, 128);
strcat(ms_rootDirName, "\\");
}
void
CFileMgr::ChangeDir(const char *dir)
{
if(*dir == '\\'){
strcpy(ms_dirName, ms_rootDirName);
dir++;
}
if(*dir != '\0'){
strcat(ms_dirName, dir);
// BUG in the game it seems, it's off by one
if(dir[strlen(dir)-1] != '\\')
strcat(ms_dirName, "\\");
}
2020-05-11 02:55:57 +00:00
mychdir(ms_dirName);
2019-05-24 17:58:32 +00:00
}
void
CFileMgr::SetDir(const char *dir)
{
strcpy(ms_dirName, ms_rootDirName);
if(*dir != '\0'){
strcat(ms_dirName, dir);
// BUG in the game it seems, it's off by one
if(dir[strlen(dir)-1] != '\\')
strcat(ms_dirName, "\\");
}
2020-05-11 02:55:57 +00:00
mychdir(ms_dirName);
2019-05-24 17:58:32 +00:00
}
void
CFileMgr::SetDirMyDocuments(void)
{
SetDir(""); // better start at the root if user directory is relative
2020-05-11 02:55:57 +00:00
mychdir(_psGetUserFilesFolder());
2019-05-24 17:58:32 +00:00
}
ssize_t
2021-01-08 12:51:50 +00:00
CFileMgr::LoadFile(const char *file, uint8 *buf, int maxlen, const char *mode)
2019-05-24 17:58:32 +00:00
{
int fd;
ssize_t n, len;
2019-05-24 17:58:32 +00:00
fd = myfopen(file, mode);
if(fd == 0)
return -1;
2019-05-24 17:58:32 +00:00
len = 0;
do{
n = myfread(buf + len, 1, 0x4000, fd);
#ifndef FIX_BUGS
if (n < 0)
2019-05-24 17:58:32 +00:00
return -1;
#endif
2019-05-24 17:58:32 +00:00
len += n;
2021-01-08 12:51:50 +00:00
assert(len < maxlen);
2019-05-24 17:58:32 +00:00
}while(n == 0x4000);
buf[len] = 0;
myfclose(fd);
return len;
}
int
CFileMgr::OpenFile(const char *file, const char *mode)
{
return myfopen(file, mode);
}
int
CFileMgr::OpenFileForWriting(const char *file)
{
return OpenFile(file, "wb");
}
2020-07-22 11:56:28 +00:00
size_t
CFileMgr::Read(int fd, const char *buf, ssize_t len)
2019-05-24 17:58:32 +00:00
{
2019-08-16 18:17:15 +00:00
return myfread((void*)buf, 1, len, fd);
2019-05-24 17:58:32 +00:00
}
2020-07-22 11:56:28 +00:00
size_t
CFileMgr::Write(int fd, const char *buf, ssize_t len)
2019-05-24 17:58:32 +00:00
{
2019-08-16 18:17:15 +00:00
return myfwrite((void*)buf, 1, len, fd);
2019-05-24 17:58:32 +00:00
}
bool
CFileMgr::Seek(int fd, int offset, int whence)
{
return !!myfseek(fd, offset, whence);
}
bool
2019-05-24 17:58:32 +00:00
CFileMgr::ReadLine(int fd, char *buf, int len)
{
return myfgets(buf, len, fd) != nil;
2019-05-24 17:58:32 +00:00
}
int
2019-05-24 17:58:32 +00:00
CFileMgr::CloseFile(int fd)
{
return myfclose(fd);
2019-05-24 17:58:32 +00:00
}
int
CFileMgr::GetErrorReadWrite(int fd)
{
return myfeof(fd);
}