DEADSOFTWARE

files: move resource manager to system drivers
authorDeaDDooMER <deaddoomer@deadsoftware.ru>
Sat, 17 Apr 2021 18:53:15 +0000 (21:53 +0300)
committerDeaDDooMER <deaddoomer@deadsoftware.ru>
Sat, 17 Apr 2021 18:53:15 +0000 (21:53 +0300)
src/files.h
src/kos32/files.c [new file with mode: 0644]
src/kos32/kos32.h
src/kos32/streams.c [new file with mode: 0644]
src/kos32/streams.h [new file with mode: 0644]
src/sdl/files.c [moved from src/files.c with 88% similarity]
src/sdl2/files.c [new file with mode: 0644]
src/sdl2/streams.c [new file with mode: 0644]
src/sdl2/streams.h [new file with mode: 0644]

index 5603209689f209514f8f61d06dc1f7454fffd977..972e1a74f6a26de947353be3fc6e2b3b06178b15 100644 (file)
@@ -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 (file)
index 0000000..69a362c
--- /dev/null
@@ -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);
+  }
+}
index a11e7911fd13aae6abcb4512d638a93738aec162..939dfb5f93a9bde48b7137cfe123d9daba444c28 100644 (file)
@@ -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 (file)
index 0000000..7d2e412
--- /dev/null
@@ -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
new file mode 100644 (file)
index 0000000..27964c7
--- /dev/null
@@ -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 */
similarity index 88%
rename from src/files.c
rename to src/sdl/files.c
index 913a5eea0358792653067faeab92a248f74eee7a..b46856d21fcc8eb63d3697dba10bf37b8d8a58ec 100644 (file)
@@ -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 (file)
index 0000000..5fb8b31
--- /dev/null
@@ -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
new file mode 100644 (file)
index 0000000..4731e63
--- /dev/null
@@ -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
new file mode 100644 (file)
index 0000000..68c381d
--- /dev/null
@@ -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 */