summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 10639e9)
raw | patch | inline | side by side (parent: 10639e9)
author | DeaDDooMER <deaddoomer@deadsoftware.ru> | |
Sat, 17 Apr 2021 18:53:15 +0000 (21:53 +0300) | ||
committer | DeaDDooMER <deaddoomer@deadsoftware.ru> | |
Sat, 17 Apr 2021 18:53:15 +0000 (21:53 +0300) |
src/files.h | patch | blob | history | |
src/kos32/files.c | [new file with mode: 0644] | patch | blob |
src/kos32/kos32.h | patch | blob | history | |
src/kos32/streams.c | [new file with mode: 0644] | patch | blob |
src/kos32/streams.h | [new file with mode: 0644] | patch | blob |
src/sdl/files.c | [moved from src/files.c with 88% similarity] | patch | blob | history |
src/sdl2/files.c | [new file with mode: 0644] | patch | blob |
src/sdl2/streams.c | [new file with mode: 0644] | patch | blob |
src/sdl2/streams.h | [new file with mode: 0644] | patch | blob |
diff --git a/src/files.h b/src/files.h
index 5603209689f209514f8f61d06dc1f7454fffd977..972e1a74f6a26de947353be3fc6e2b3b06178b15 100644 (file)
--- a/src/files.h
+++ b/src/files.h
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
--- /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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "glob.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#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 a11e7911fd13aae6abcb4512d638a93738aec162..939dfb5f93a9bde48b7137cfe123d9daba444c28 100644 (file)
--- a/src/kos32/kos32.h
+++ b/src/kos32/kos32.h
#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
--- /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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "streams.h"
+#include "kos32.h"
+#include <assert.h>
+#include <string.h>
+
+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
--- /dev/null
+++ b/src/kos32/streams.h
@@ -0,0 +1,17 @@
+#ifndef D2D_KOS32_STREAMS_H_INCLUDED
+#define D2D_KOS32_STREAMS_H_INCLUDED
+
+#include <common/streams.h>
+
+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 913a5eea0358792653067faeab92a248f74eee7a..b46856d21fcc8eb63d3697dba10bf37b8d8a58ec 100644 (file)
rename from src/files.c
rename to src/sdl/files.c
index 913a5eea0358792653067faeab92a248f74eee7a..b46856d21fcc8eb63d3697dba10bf37b8d8a58ec 100644 (file)
--- a/src/files.c
+++ b/src/sdl/files.c
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
--- /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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "glob.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "files.h"
+#include "error.h"
+
+#include "map.h" // MAP_load
+#include "save.h" // SAVE_getname
+
+#ifdef UNIX
+# include <sys/stat.h>
+#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
--- /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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "streams.h"
+#include <assert.h>
+
+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
--- /dev/null
+++ b/src/sdl2/streams.h
@@ -0,0 +1,16 @@
+#ifndef D2D_SDL2_STREAMS_H_INCLUDED
+#define D2D_SDL2_STREAMS_H_INCLUDED
+
+#include <SDL2/SDL.h>
+#include <common/streams.h>
+
+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 */