aboutsummaryrefslogtreecommitdiff
path: root/src/container
diff options
context:
space:
mode:
authorXavier Del Campo Romero <xavi.dcr@tutanota.com>2021-07-03 00:49:03 +0200
committerXavier Del Campo Romero <xavi.dcr@tutanota.com>2022-03-30 08:20:20 +0200
commit6b9f686913efc3725b2690033cd4f398e07076ba (patch)
treee9aa91a6b9f617d78123ebe7ad272fc42a60d306 /src/container
parentc9e6ae44a9aeb89b3f48f3443d6baa80103f7445 (diff)
downloadjancity-6b9f686913efc3725b2690033cd4f398e07076ba.tar.gz
Add project source code
Diffstat (limited to 'src/container')
-rw-r--r--src/container/CMakeLists.txt11
-rw-r--r--src/container/inc/container.h43
-rw-r--r--src/container/ps1/inc/container/port.h6
-rw-r--r--src/container/sdl-1.2/inc/container/port.h6
-rw-r--r--src/container/src/container.c225
5 files changed, 291 insertions, 0 deletions
diff --git a/src/container/CMakeLists.txt b/src/container/CMakeLists.txt
new file mode 100644
index 0000000..740fe37
--- /dev/null
+++ b/src/container/CMakeLists.txt
@@ -0,0 +1,11 @@
+set(inc "inc")
+
+if(PS1_BUILD)
+ set(inc ${inc} "ps1/inc")
+elseif(SDL1_2_BUILD)
+ set(inc ${inc} "sdl-1.2/inc")
+endif()
+
+add_library(container "src/container.c")
+target_include_directories(container PUBLIC ${inc})
+target_link_libraries(container PUBLIC gfx sfx)
diff --git a/src/container/inc/container.h b/src/container/inc/container.h
new file mode 100644
index 0000000..59ab5fd
--- /dev/null
+++ b/src/container/inc/container.h
@@ -0,0 +1,43 @@
+#ifndef CONTAINER_H
+#define CONTAINER_H
+
+#include <container/port.h>
+#include <gfx.h>
+#include <sfx.h>
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+struct container
+{
+ const char *path;
+
+ enum
+ {
+ CONTAINER_TYPE_SPRITE,
+ CONTAINER_TYPE_SOUND
+ } type;
+
+ union
+ {
+ struct sprite *sprite;
+ struct sound *sound;
+ } data;
+
+ struct container_rt
+ {
+ struct container *c;
+ } *rt;
+};
+
+int container_load_ex(const char *path, const struct container *list, size_t n);
+void container_free(const struct container *list, size_t n);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CONTAINER_H */
diff --git a/src/container/ps1/inc/container/port.h b/src/container/ps1/inc/container/port.h
new file mode 100644
index 0000000..aaf2f96
--- /dev/null
+++ b/src/container/ps1/inc/container/port.h
@@ -0,0 +1,6 @@
+#ifndef CONTAINER_PS1_H
+#define CONTAINER_PS1_H
+
+#define container_load(path, list, n) container_load_ex("cdrom:\\"path";1", list, n)
+
+#endif /* CONTAINER_PS1_H */
diff --git a/src/container/sdl-1.2/inc/container/port.h b/src/container/sdl-1.2/inc/container/port.h
new file mode 100644
index 0000000..b58697d
--- /dev/null
+++ b/src/container/sdl-1.2/inc/container/port.h
@@ -0,0 +1,6 @@
+#ifndef CONTAINER_SDL_12_H
+#define CONTAINER_SDL_12_H
+
+#define container_load(path, list, n) container_load_ex(path, list, n)
+
+#endif /* CONTAINER_SDL_12_H */
diff --git a/src/container/src/container.c b/src/container/src/container.c
new file mode 100644
index 0000000..008ca58
--- /dev/null
+++ b/src/container/src/container.c
@@ -0,0 +1,225 @@
+#include <container.h>
+#include <gfx.h>
+#include <sfx.h>
+#include <errno.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static int readstr(char *const str, const size_t n, FILE *const f)
+{
+ int ret = -1;
+ size_t i = 0;
+
+ do
+ {
+ if (i >= n)
+ {
+ fprintf(stderr, "%s: string too long (> %zu bytes): %*.s\n",
+ __func__, n, (int)n, str);
+ goto end;
+ }
+ else if (!fread(&str[i], sizeof *str, 1, f))
+ {
+ fprintf(stderr, "%s: expected null-terminated string\n", __func__);
+ goto end;
+ }
+ } while (str[i++]);
+
+ ret = 0;
+
+end:
+ return ret;
+}
+
+static int get_file_size(size_t *const sz, FILE *const f)
+{
+ char szstr[sizeof "2147483647"];
+
+ if (readstr(szstr, sizeof szstr, f))
+ return -1;
+
+ errno = 0;
+ const unsigned long val = strtoul(szstr, NULL, 10);
+
+ if (errno)
+ {
+ fprintf(stderr, "%s: strtoul(3): %s\n", __func__, strerror(errno));
+ return -1;
+ }
+
+ *sz = val;
+ return 0;
+}
+
+static int read_file_contents(const struct container *const el, FILE *const f,
+ const long init_off, const size_t sz)
+{
+ int ret = -1;
+
+ switch (el->type)
+ {
+ case CONTAINER_TYPE_SPRITE:
+ if (sprite_from_fp(el->data.sprite, f))
+ goto end;
+
+ break;
+
+ case CONTAINER_TYPE_SOUND:
+ if (sfx_sound_from_fp(el->data.sound, f))
+ goto end;
+
+ break;
+ }
+
+ const long off = ftell(f);
+
+ if (off < 0)
+ {
+ fprintf(stderr, "%s:%d: fseek failed: %s\n",
+ __func__, __LINE__, strerror(errno));
+ goto end;
+ }
+ else if (off > init_off + sz)
+ {
+ fprintf(stderr, "%s: %s: detected read past file contents\n",
+ __func__, el->path);
+ goto end;
+ }
+ else if (off != init_off + sz)
+ {
+ fprintf(stderr, "only %ld bytes read, %ld expected\n",
+ off, init_off + sz);
+ goto end;
+ }
+
+ ret = 0;
+
+end:
+ return ret;
+}
+
+static const struct container *find_element(const struct container *const list,
+ const size_t n, FILE *const f)
+{
+ char name[128];
+
+ if (readstr(name, sizeof name, f))
+ return NULL;
+
+ for (size_t i = 0; i < n; i++)
+ {
+ const struct container *const el = &list[i];
+
+ if (!strcmp(el->path, name))
+ return el;
+ }
+
+ fprintf(stderr, "file %s not found on the list\n", name);
+ return NULL;
+}
+
+static int read_element(const struct container *const list, const size_t n,
+ FILE *const f, bool *const done)
+{
+ int ret = -1;
+ long init_off;
+ const struct container *el = NULL;
+ size_t sz;
+
+ if (!(el = find_element(list, n, f)))
+ goto end;
+ else if (get_file_size(&sz, f))
+ goto end;
+ else if ((init_off = ftell(f)) < 0)
+ {
+ fprintf(stderr, "%s:%d: fseek failed: %s\n",
+ __func__, __LINE__, strerror(errno));
+ goto end;
+ }
+ else if (read_file_contents(el, f, init_off, sz))
+ goto end;
+
+ done[el - list] = true;
+ ret = 0;
+
+end:
+ return ret;
+}
+
+static int read_all_elements(const struct container *const list, const size_t n,
+ FILE *const f)
+{
+ int ret = -1;
+ /* VLAs are generally frowned upon, but we can safely assume
+ * 'n' is reasonably low. */
+ bool done[n];
+
+ memset(&done, 0, sizeof done);
+
+ for (size_t i = 0; i < sizeof done / sizeof *done; i++)
+ if (feof(f) || ferror(f)
+ || read_element(list, n, f, done))
+ goto end;
+
+ for (size_t i = 0; i < sizeof done / sizeof *done; i++)
+ {
+ if (!done[i])
+ {
+ fprintf(stderr, "%s: %s not found inside container file\n",
+ __func__, list[i].path);
+ goto end;
+ }
+ }
+
+ ret = 0;
+
+end:
+ return ret;
+}
+
+void container_free(const struct container *const list, const size_t n)
+{
+ if (!list)
+ return;
+
+ for (size_t i = 0; i < n; i++)
+ {
+ const struct container *const el = &list[i];
+
+ switch (el->type)
+ {
+ case CONTAINER_TYPE_SPRITE:
+ sprite_free(el->data.sprite);
+ break;
+
+ case CONTAINER_TYPE_SOUND:
+ sfx_free(el->data.sound);
+ break;
+ }
+ }
+}
+
+int container_load_ex(const char *const path, const struct container *const list,
+ const size_t n)
+{
+ int ret = -1;
+ FILE *f = NULL;
+
+ if (!(f = fopen(path, "rb")))
+ {
+ fprintf(stderr, "could not open %s: %s\n", path, strerror(errno));
+ goto end;
+ }
+ else if (read_all_elements(list, n, f))
+ goto end;
+
+ ret = 0;
+
+end:
+ if (f)
+ fclose(f);
+
+ return ret;
+}