From 30a1e51f4672eed675ef310d67adabc36e3146fc Mon Sep 17 00:00:00 2001 From: DeaDDooMER Date: Sat, 17 Apr 2021 21:53:15 +0300 Subject: [PATCH] files: move resource manager to system drivers --- src/files.h | 19 +++- src/kos32/files.c | 200 +++++++++++++++++++++++++++++++++++++++ src/kos32/kos32.h | 120 +++++++++++++++++++++++ src/kos32/streams.c | 159 +++++++++++++++++++++++++++++++ src/kos32/streams.h | 17 ++++ src/{ => sdl}/files.c | 16 ---- src/sdl2/files.c | 215 ++++++++++++++++++++++++++++++++++++++++++ src/sdl2/streams.c | 99 +++++++++++++++++++ src/sdl2/streams.h | 16 ++++ 9 files changed, 844 insertions(+), 17 deletions(-) create mode 100644 src/kos32/files.c create mode 100644 src/kos32/streams.c create mode 100644 src/kos32/streams.h rename src/{ => sdl}/files.c (88%) create mode 100644 src/sdl2/files.c create mode 100644 src/sdl2/streams.c create mode 100644 src/sdl2/streams.h diff --git a/src/files.h b/src/files.h index 5603209..972e1a7 100644 --- a/src/files.h +++ b/src/files.h @@ -32,9 +32,26 @@ void F_initwads (void); int F_findres (const char n[8]); int F_getresid (const char n[8]); void F_getresname (char n[8], int r); -int F_getsprid (const char n[4], int s, int d, char *dir); int F_getreslen (int r); +// Get sprite resource id. +// Sprite name has following format: +// (nnnn)('A'+s)('0'+d)[('A'+s)('0'+d)] +// Letter means animation frame +// A for first, B for second... +// Number means direction +// 0 = front +// 1 = left +// 2 = right +// Optional part means that this file can be used for differnt frame/direction. +// Note that if found FRONT direction for this frame than it UNCONDITIONALLY used. +// Note that search performed between markers S_START and S_END in order as paced in wad. +// int n[4] -- sprite name +// int s -- sprite frame +// int d -- sprite direction +// char *dir -- out flag "alternative used" +int F_getsprid (const char n[4], int s, int d, char *dir); + // void F_nextmus (char *s); // void F_randmus (char *s); diff --git a/src/kos32/files.c b/src/kos32/files.c new file mode 100644 index 0000000..69a362c --- /dev/null +++ b/src/kos32/files.c @@ -0,0 +1,200 @@ +/* Copyright (C) 1996-1997 Aleksey Volynskov + * Copyright (C) 2011 Rambo + * Copyright (C) 2020 SovietPony + * + * 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, version 3 of the License ONLY. + * + * 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, see . + */ + +#include "glob.h" +#include +#include +#include +#include +#include "files.h" +#include "error.h" + +#include "map.h" // MAP_load +#include "save.h" // SAVE_getname + +#include "kos32/streams.h" +#include "common/streams.h" +#include "common/wadres.h" +#include "common/cp866.h" + +int d_start, d_end; + +char savname[SAVE_MAX][SAVE_MAXLEN]; +char savok[SAVE_MAX]; + +static int m_start, m_end; +static int s_start, s_end; + +void F_addwad (const char *fn) { + static int i = 0; + static KOS32_Stream wadh[MAX_WADS]; + if (i < MAX_WADS) { + if (KOS32_Open(&wadh[i], fn)) { + if (WADRES_addwad(&wadh[i].base)) { + i += 1; + } else { + ERR_failinit("Invalid WAD %s", fn); + } + } else { + ERR_failinit("Unable to add WAD %s", fn); + } + } else { + ERR_failinit("Too many wads"); + } +} + +void F_initwads (void) { + if (!WADRES_rehash()) { + ERR_failinit("F_initwads: failed rehash"); + } + d_start = F_getresid("D_START"); + d_end = F_getresid("D_END"); + m_start = F_getresid("M_START"); + m_end = F_getresid("M_END"); + s_start = F_getresid("S_START"); + s_end = F_getresid("S_END"); +} + +int F_findres (const char n[8]) { + return WADRES_find(n); +} + +int F_getresid (const char n[8]) { + int i = F_findres(n); + if (i == -1) { + ERR_fatal("F_getresid: resource %.8s not found", n); + } + return i; +} + +void F_getresname (char n[8], int r) { + WADRES_getname(r, n); +} + +int F_getsprid (const char n[4], int s, int d, char *dir) { + s += 'A'; + d += '0'; + for (int i = s_start + 1; i < s_end; i++) { + char wn[8]; + byte a, b; + WADRES_getname(i, wn); + if (cp866_strncasecmp(wn, n, 4) == 0 && (wn[4] == s || wn[6] == s)) { + a = wn[4] == s ? wn[5] : 0; + b = wn[6] == s ? wn[7] : 0; + if (a == '0' || b == '0' || a == d || b == d) { + if (dir != NULL) { + *dir = (a != '0' && b == '0') || (a != d && b == d); + } + return i; + } + } + } + ERR_fatal("F_getsprid: image %.4s%c%c not found", n, s, d); + return -1; +} + +int F_getreslen (int r) { + return WADRES_getsize(r); +} + +/* +void F_nextmus (char *s) { + int i = F_findres(s); + if (i <= m_start || i >= m_end) { + i = m_start; + } + for (++i; ; ++i) { + if (i >= m_end) { + i = m_start + 1; + } + WADRES_getname(i, s); + if (cp866_strcasecmp(s, "MENU") == 0 || + cp866_strcasecmp(s, "INTERMUS") == 0 || + cp866_strcasecmp(s, "\x8a\x8e\x8d\x85\x96\x0") == 0) { + continue; + } + if (cp866_strncasecmp(s, "DMI", 3) != 0) { + break; + } + } +} + +void F_randmus (char *s) { + int i; + int n = myrand(10); + for (i = 0; i < n; i++) { + F_nextmus(s); + } +} +*/ + +void F_loadmap (char n[8]) { + int id = F_getresid(n); + if (id != -1) { + Stream *r = WADRES_getbasereader(id); + long offset = WADRES_getoffset(id); + stream_setpos(r, offset); + if (!MAP_load(r)) { + ERR_fatal("Failed to load map"); + } + } else { + ERR_fatal("Failed to load map: resource %.8s not found", n); + } +} + +static char *getsavfpname (int n, int ro) { + static char fn[] = "savgame0.dat"; + static char p[100]; + fn[7] = n + '0'; + strcpy(p, fn); + return p; +} + +void F_getsavnames (void) { + KOS32_Stream rd; + for (int i = 0; i < SAVE_MAX; ++i) { + savok[i] = 0; + char *p = getsavfpname(i, 1); + if (KOS32_Open(&rd, p)) { + savok[i] = SAVE_getname(&rd.base, savname[i]); + KOS32_Close(&rd); + } + if (!savok[i]) { + memset(savname[i], 0, 24); + } else { + savname[i][23] = 0; + } + } +} + +void F_loadgame (int n) { + KOS32_Stream rd; + char *p = getsavfpname(n, 1); + if (KOS32_Open(&rd, p)) { + SAVE_load(&rd.base); + KOS32_Close(&rd); + } +} + +void F_savegame (int n, char *s) { + KOS32_Stream wr; + char *p = getsavfpname(n, 0); + if (KOS32_Create(&wr, p)) { + SAVE_save(&wr.base, s); + KOS32_Close(&wr); + } +} diff --git a/src/kos32/kos32.h b/src/kos32/kos32.h index a11e791..939dfb5 100644 --- a/src/kos32/kos32.h +++ b/src/kos32/kos32.h @@ -409,4 +409,124 @@ static inline void Delay (int time) { #define KOS32_SC_EXTENDED_PAUSE 0xE1 /* pause key seq */ +#pragma pack(push, 1) +struct FileExt { + int fn; + int a, b, c, d; + int enc; + const void *path; +}; + +struct FileTime { + char s, m, h, reserved; +}; + +struct FileDate { + char d, m; + unsigned short y; +}; + +struct FileInfo { + int attr; + int enc; + struct FileTime ctime; + struct FileDate cdate; + struct FileTime atime; + struct FileDate cdate; + struct FileTime mtime; + struct FileDate mdate; + long long size; + union { + char cp866[264]; + short utf16[260]; + char utf8[520]; + }; +}; +#pragma pack(pop) + +#define KOS32_READ_FILE 0 +#define KOS32_READ_FOLDER 1 +#define KOS32_CREATE_FILE 2 +#define KOS32_WRITE_FILE 3 +#define KOS32_SET_END 4 +#define KOS32_GET_INFO 5 +#define KOS32_SET_INFO 6 +#define KOS32_START_APP 7 +#define KOS32_DELETE 8 +#define KOS32_CREATE_FOLDER 9 +#define KOS32_RENAME 10 + +#define KOS32_FILE_SUCCESS 0 +#define KOS32_FILE_NOT_SUPPORTED 2 +#define KOS32_FILE_UNKNOWN_FS 3 +#define KOS32_FILE_NOT_FOUND 5 +#define KOS32_FILE_EOF 6 +#define KOS32_FILE_INVALID_PTR 7 +#define KOS32_FILE_DISK_FULL 8 +#define KOS32_FILE_FS_ERROR 9 +#define KOS32_FILE_ACCESS_DENIED 10 +#define KOS32_FILE_DEVICE_ERROR 11 +#define KOS32_FILE_OUT_OF_MEMORY 12 + +#define KOS32_CP866 1 +#define KOS32_UTF16 2 +#define KOS32_UTF8 3 + +#define KOS32_ATTR_READONLY 0 +#define KOS32_ATTR_HIDDEN 1 +#define KOS32_ATTR_SYSTEM 2 +#define KOS32_ATTR_VOLUME 3 +#define KOS32_ATTR_FOLDER 4 +#define KOS32_ATTR_ARCHIVED 5 + +#define KOS32_ATTR_MASK_READONLY (1 << KOS32_ATTR_READONLY) +#define KOS32_ATTR_MASK_HIDDEN (1 << KOS32_ATTR_HIDDEN) +#define KOS32_ATTR_MASK_SYSTEM (1 << KOS32_ATTR_SYSTEM) +#define KOS32_ATTR_MASK_VOLUME (1 << KOS32_ATTR_VOLUME) +#define KOS32_ATTR_MASK_FOLDER (1 << KOS32_ATTR_FOLDER) +#define KOS32_ATTR_MASK_ARCHIVED (1 << KOS32_ATTR_ARCHIVED) + +static inline int FileExt (struct FileExt *info, int *ret) { + int ret1, ret2; + __asm__ __volatile__ ( + "int $0x40" + : "=a" (ret1), + "=b" (ret2) + : "a" (80), + "b" (info) + : "memory" + ); + if (ret) *ret = ret2; + return ret1; +} + +/* --- fn 30.4 --- */ +static inline void SetCurrentFolderEnc (char *path, int enc) { + __asm__ __volatile__ ( + "int $0x40" + : + : "a" (30), + "b" (4), + "c" (path), + "d" (enc) + : "memory" + ); +} + +/* --- fn 30.5 --- */ +static inline int GetCurrentFolderEnc (char *buf, int maxlen, int enc) { + int len; + __asm__ __volatile__ ( + "int $0x40" + : "=a" (len) + : "a" (30), + "b" (5), + "c" (buf), + "d" (maxlen), + "S" (enc) + : "memory" + ); + return len; +} + #endif /* KOS32_H */ diff --git a/src/kos32/streams.c b/src/kos32/streams.c new file mode 100644 index 0000000..7d2e412 --- /dev/null +++ b/src/kos32/streams.c @@ -0,0 +1,159 @@ +/* Copyright (C) 2020 SovietPony + * + * 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, version 3 of the License ONLY. + * + * 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, see . + */ + +#include "streams.h" +#include "kos32.h" +#include +#include + +static inline int ReadFile (int offset, void *data, size_t len, int enc, const void *path, int *count) { + struct FileExt info = { KOS32_READ_FILE, offset, 0/*high_offset*/, (int)len, (int)data, enc, path }; + return FileExt(&info, count); +} + +static inline int CreateFile (const void *data, size_t len, int enc, const void *path, int *count) { + struct FileExt info = { KOS32_CREATE_FILE, 0, 0, (int)len, (int)data, enc, path }; + return FileExt(&info, count); +} + +static inline int WriteFile (int offset, const void *data, size_t len, int enc, const void *path, int *count) { + struct FileExt info = { KOS32_WRITE_FILE, offset, 0/*high_offset*/, (int)len, (int)data, enc, path }; + return FileExt(&info, count); +} + +static inline int InfoFile (int flags, struct FileInfo *bdfe, int enc, const void *path) { + struct FileExt info = { KOS32_GET_INFO, 0, flags, 0, (int)bdfe, enc, path }; + return FileExt(&info, NULL); +} + +static inline int StartApp (int flags, const char *params, int enc, const void *path) { + struct FileExt info = { KOS32_START_APP, flags, (int)params, 0, 0, enc, path }; + return FileExt(&info, NULL); +} + +static inline int DeleteFile (int enc, const void *path) { + struct FileExt info = { KOS32_DELETE, 0, 0, 0, 0, enc, path }; + return FileExt(&info, NULL); +} + +static long KOS32_GetPos (Stream *r) { + KOS32_Stream *rd = (KOS32_Stream*)r; + assert(rd != NULL); + assert(rd->name[0] != 0); + return rd->pos; +} + +static void KOS32_SetPos (Stream *r, long pos) { + KOS32_Stream *rd = (KOS32_Stream*)r; + assert(rd != NULL); + assert(rd->name[0] != 0); + assert(pos >= 0); + rd->pos = pos; +} + +static long KOS32_GetLen (Stream *r) { + KOS32_Stream *rd = (KOS32_Stream*)r; + assert(rd != NULL); + assert(rd->name[0] != 0); + struct FileInfo info; + int res = InfoFile(0, &info, KOS32_UTF8, rd->name); + assert(res == KOS32_FILE_SUCCESS); + return info.size; +} + +static void KOS32_Read (Stream *r, void *data, size_t size, size_t n) { + KOS32_Stream *rd = (KOS32_Stream*)r; + assert(rd != NULL); + assert(rd->name[0] != 0); + long long len = (long long)size * n; + int count = 0; + int res = ReadFile(rd->pos, data, len, KOS32_UTF8, rd->name, &count); + assert(res == KOS32_FILE_SUCCESS); + assert(count == len); + rd->pos += len; +} + +static void KOS32_Write (Stream *w, const void *data, size_t size, size_t n) { + KOS32_Stream *wr = (KOS32_Stream*)w; + assert(wr != NULL); + assert(wr->name[0] != 0); + long long len = (long long)size * n; + int count = 0; + int res = WriteFile(wr->pos, data, len, KOS32_UTF8, wr->name, &count); + assert(res == KOS32_FILE_SUCCESS); + assert(count == len); + wr->pos += len; +} + +void KOS32_Assign (KOS32_Stream *s, const char *name, long pos) { + assert(s != NULL); + assert(name != NULL); + assert(pos >= 0); + s->base.getpos = KOS32_GetPos; + s->base.setpos = KOS32_SetPos; + s->base.getlen = KOS32_GetLen; + s->base.read = KOS32_Read; + s->base.write = KOS32_Write; + strncpy(s->name, name, 264); + s->pos = pos; +} + +static void getpath (char *buf, int len, const char *name) { + int i = GetCurrentFolderEnc(buf, len, KOS32_UTF8); + buf[i - 1] = '/'; + strcpy(&buf[i], name); +} + +static inline is_directory (struct FileInfo *info) { + return !!(info->attr & (KOS32_ATTR_MASK_VOLUME | KOS32_ATTR_MASK_FOLDER)); +} + +int KOS32_Open (KOS32_Stream *s, const char *name) { + assert(s != NULL); + assert(name != NULL); + char path[264]; + getpath(path, 264, name); + struct FileInfo info; + int res = InfoFile(0, &info, KOS32_UTF8, path); + if (res == KOS32_FILE_SUCCESS && !is_directory(&info)) { + KOS32_Assign(s, name, 0); + return 1; + } + return 0; +} + +int KOS32_Create (KOS32_Stream *s, const char *name) { + assert(s != NULL); + assert(name != NULL); + char path[264]; + getpath(path, 264, name); + int res = CreateFile(NULL, 0, KOS32_UTF8, path, NULL); + if (res == KOS32_FILE_SUCCESS) { + KOS32_Assign(s, name, 0); + return 1; + } + return 0; +} + +void KOS32_Close (KOS32_Stream *s) { + assert(s != NULL); + s->base.getpos = NULL; + s->base.setpos = NULL; + s->base.getlen = NULL; + s->base.read = NULL; + s->base.write = NULL; + s->name[0] = 0; + s->pos = 0; +} diff --git a/src/kos32/streams.h b/src/kos32/streams.h new file mode 100644 index 0000000..27964c7 --- /dev/null +++ b/src/kos32/streams.h @@ -0,0 +1,17 @@ +#ifndef D2D_KOS32_STREAMS_H_INCLUDED +#define D2D_KOS32_STREAMS_H_INCLUDED + +#include + +typedef struct KOS32_Stream { + Stream base; + char name[264]; + long pos; +} KOS32_Stream; + +void KOS32_Assign (KOS32_Stream *s, const char *name, long pos); +int KOS32_Open (KOS32_Stream *s, const char *name); +int KOS32_Create (KOS32_Stream *s, const char *name); +void KOS32_Close (KOS32_Stream *s); + +#endif /* D2D_KOS32_STREAMS_H_INCLUDED */ diff --git a/src/files.c b/src/sdl/files.c similarity index 88% rename from src/files.c rename to src/sdl/files.c index 913a5ee..b46856d 100644 --- a/src/files.c +++ b/src/sdl/files.c @@ -89,22 +89,6 @@ void F_getresname (char n[8], int r) { WADRES_getname(r, n); } -// Get sprite resource id. -// Sprite name has following format: -// (nnnn)('A'+s)('0'+d)[('A'+s)('0'+d)] -// Letter means animation frame -// A for first, B for second... -// Number means direction -// 0 = front -// 1 = left -// 2 = right -// Optional part means that this file can be used for differnt frame/direction. -// Note that if found FRONT direction for this frame than it UNCONDITIONALLY used. -// Note that search performed between markers S_START and S_END in order as paced in wad. -// int n[4] -- sprite name -// int s -- sprite frame -// int d -- sprite direction -// char *dir -- out flag "alternative used" ( int F_getsprid (const char n[4], int s, int d, char *dir) { s += 'A'; d += '0'; diff --git a/src/sdl2/files.c b/src/sdl2/files.c new file mode 100644 index 0000000..5fb8b31 --- /dev/null +++ b/src/sdl2/files.c @@ -0,0 +1,215 @@ +/* Copyright (C) 1996-1997 Aleksey Volynskov + * Copyright (C) 2011 Rambo + * Copyright (C) 2020 SovietPony + * + * 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, version 3 of the License ONLY. + * + * 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, see . + */ + +#include "glob.h" +#include +#include +#include +#include +#include "files.h" +#include "error.h" + +#include "map.h" // MAP_load +#include "save.h" // SAVE_getname + +#ifdef UNIX +# include +#endif + +#include "sdl2/streams.h" +#include "common/streams.h" +#include "common/wadres.h" +#include "common/cp866.h" + +int d_start, d_end; + +char savname[SAVE_MAX][SAVE_MAXLEN]; +char savok[SAVE_MAX]; + +static int m_start, m_end; +static int s_start, s_end; + +void F_addwad (const char *fn) { + static int i = 0; + static SDLRW_Stream wadh[MAX_WADS]; + if (i < MAX_WADS) { + if (SDLRW_Open(&wadh[i], fn, "rb")) { + if (WADRES_addwad(&wadh[i].base)) { + i += 1; + } else { + ERR_failinit("Invalid WAD %s", fn); + } + } else { + ERR_failinit("Unable to add WAD %s", fn); + } + } else { + ERR_failinit("Too many wads"); + } +} + +void F_initwads (void) { + if (!WADRES_rehash()) { + ERR_failinit("F_initwads: failed rehash"); + } + d_start = F_getresid("D_START"); + d_end = F_getresid("D_END"); + m_start = F_getresid("M_START"); + m_end = F_getresid("M_END"); + s_start = F_getresid("S_START"); + s_end = F_getresid("S_END"); +} + +int F_findres (const char n[8]) { + return WADRES_find(n); +} + +int F_getresid (const char n[8]) { + int i = F_findres(n); + if (i == -1) { + ERR_fatal("F_getresid: resource %.8s not found", n); + } + return i; +} + +void F_getresname (char n[8], int r) { + WADRES_getname(r, n); +} + +int F_getsprid (const char n[4], int s, int d, char *dir) { + s += 'A'; + d += '0'; + for (int i = s_start + 1; i < s_end; i++) { + char wn[8]; + byte a, b; + WADRES_getname(i, wn); + if (cp866_strncasecmp(wn, n, 4) == 0 && (wn[4] == s || wn[6] == s)) { + a = wn[4] == s ? wn[5] : 0; + b = wn[6] == s ? wn[7] : 0; + if (a == '0' || b == '0' || a == d || b == d) { + if (dir != NULL) { + *dir = (a != '0' && b == '0') || (a != d && b == d); + } + return i; + } + } + } + ERR_fatal("F_getsprid: image %.4s%c%c not found", n, s, d); + return -1; +} + +int F_getreslen (int r) { + return WADRES_getsize(r); +} + +/* +void F_nextmus (char *s) { + int i = F_findres(s); + if (i <= m_start || i >= m_end) { + i = m_start; + } + for (++i; ; ++i) { + if (i >= m_end) { + i = m_start + 1; + } + WADRES_getname(i, s); + if (cp866_strcasecmp(s, "MENU") == 0 || + cp866_strcasecmp(s, "INTERMUS") == 0 || + cp866_strcasecmp(s, "\x8a\x8e\x8d\x85\x96\x0") == 0) { + continue; + } + if (cp866_strncasecmp(s, "DMI", 3) != 0) { + break; + } + } +} + +void F_randmus (char *s) { + int i; + int n = myrand(10); + for (i = 0; i < n; i++) { + F_nextmus(s); + } +} +*/ + +void F_loadmap (char n[8]) { + int id = F_getresid(n); + if (id != -1) { + Stream *r = WADRES_getbasereader(id); + long offset = WADRES_getoffset(id); + stream_setpos(r, offset); + if (!MAP_load(r)) { + ERR_fatal("Failed to load map"); + } + } else { + ERR_fatal("Failed to load map: resource %.8s not found", n); + } +} + +static char *getsavfpname (int n, int ro) { + static char fn[] = "savgame0.dat"; + static char p[100]; + fn[7] = n + '0'; +#ifdef UNIX + char *e = getenv("HOME"); + strncpy(p, e, 60); + strcat(p, "/.flatwaifu"); + if (!ro) { + mkdir(p, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + } + strcat(p, "/"); + strcat(p, fn); +#else + strcpy(p, fn); +#endif + return p; +} + +void F_getsavnames (void) { + SDLRW_Stream rd; + for (int i = 0; i < SAVE_MAX; ++i) { + savok[i] = 0; + char *p = getsavfpname(i, 1); + if (SDLRW_Open(&rd, p, "rb")) { + savok[i] = SAVE_getname(&rd.base, savname[i]); + SDLRW_Close(&rd); + } + if (!savok[i]) { + memset(savname[i], 0, 24); + } else { + savname[i][23] = 0; + } + } +} + +void F_loadgame (int n) { + SDLRW_Stream rd; + char *p = getsavfpname(n, 1); + if (SDLRW_Open(&rd, p, "rb")) { + SAVE_load(&rd.base); + SDLRW_Close(&rd); + } +} + +void F_savegame (int n, char *s) { + SDLRW_Stream wr; + char *p = getsavfpname(n, 0); + if (SDLRW_Open(&wr, p, "wb")) { + SAVE_save(&wr.base, s); + SDLRW_Close(&wr); + } +} diff --git a/src/sdl2/streams.c b/src/sdl2/streams.c new file mode 100644 index 0000000..4731e63 --- /dev/null +++ b/src/sdl2/streams.c @@ -0,0 +1,99 @@ +/* Copyright (C) 2020 SovietPony + * + * 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, version 3 of the License ONLY. + * + * 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, see . + */ + +#include "streams.h" +#include + +static long SDLRW_GetPos (Stream *r) { + SDLRW_Stream *rd = (SDLRW_Stream*)r; + assert(rd != NULL); + assert(rd->io != NULL); + Sint64 pos = SDL_RWtell(rd->io); + assert(res != -1); // fail + return pos; +} + +static void SDLRW_SetPos (Stream *r, long pos) { + SDLRW_Stream *rd = (SDLRW_Stream*)r; + assert(rd != NULL); + assert(rd->io != NULL); + Sint64 res = SDL_RWseek(rd->io, pos, RW_SEEK_SET); + assert(res != pos); // fail +} + +static long SDLRW_GetLen (Stream *r) { + SDLRW_Stream *rd = (SDLRW_Stream*)r; + assert(rd != NULL); + assert(rd->io != NULL); + Sint64 pos = SDL_RWtell(rd->io); + assert(pos != -1); // fail + Sint64 len = SDL_RWseek(rd->io, 0, RW_SEEK_END); + assert(len == -1); // fail + Sint64 res = SDL_RWseek(rd->io, pos, RW_SEEK_SET); + assert(res != pos); // fail + return len; +} + +static void SDLRW_Read (Stream *r, void *data, size_t size, size_t n) { + SDLRW_Stream *rd = (SDLRW_Stream*)r; + assert(rd != NULL); + assert(rd->io != NULL); + size_t res = SDL_RWread(rd->io, data, size, n); + assert(res == n); // fail +} + +static void SDLRW_Write (Stream *w, const void *data, size_t size, size_t n) { + SDLRW_Stream *wr = (SDLRW_Stream*)w; + assert(wr != NULL); + assert(wr->io != NULL); + size_t res = SDL_RWwrite(wr->io, data, size, n); + assert(res == n); // fail +} + +void SDLRW_Assign (SDLRW_Stream *s, SDL_RWops *io) { + assert(s != NULL); + assert(io != NULL); + s->base.getpos = SDLRW_GetPos; + s->base.setpos = SDLRW_SetPos; + s->base.getlen = SDLRW_GetLen; + s->base.read = SDLRW_Read; + s->base.write = SDLRW_Write; + s->io = io; +} + +int SDLRW_Open (SDLRW_Stream *s, const char *name, const char *mode) { + assert(s != NULL); + assert(name != NULL); + assert(mode != NULL); + SDL_RWops *io = SDL_RWFromFile(name, mode); + if (io != NULL) { + SDLRW_Assign(s, io); + return 1; + } + return 0; +} + +void SDLRW_Close (SDLRW_Stream *s) { + assert(s != NULL); + if (s->io) { + SDL_RWclose(s->io); + } + s->base.getpos = NULL; + s->base.setpos = NULL; + s->base.getlen = NULL; + s->base.read = NULL; + s->base.write = NULL; + s->io = NULL; +} diff --git a/src/sdl2/streams.h b/src/sdl2/streams.h new file mode 100644 index 0000000..68c381d --- /dev/null +++ b/src/sdl2/streams.h @@ -0,0 +1,16 @@ +#ifndef D2D_SDL2_STREAMS_H_INCLUDED +#define D2D_SDL2_STREAMS_H_INCLUDED + +#include +#include + +typedef struct SDLRW_Stream { + Stream base; + SDL_RWops *io; +} SDLRW_Stream; + +void SDLRW_Assign (SDLRW_Stream *s, SDL_RWops *io); +int SDLRW_Open (SDLRW_Stream *s, const char *name, const char *mode); +void SDLRW_Close (SDLRW_Stream *s); + +#endif /* D2D_SDL2_STREAMS_H_INCLUDED */ -- 2.29.2