diff --git a/include/system4/ald.h b/include/system4/ald.h index 0e4e382..ceb435f 100644 --- a/include/system4/ald.h +++ b/include/system4/ald.h @@ -24,23 +24,13 @@ #include #include #include +#include "system4/archive.h" #define ALD_FILEMAX 255 #define ALD_DATAMAX 65535 -enum ald_error { - ALD_SUCCESS, - ALD_FILE_ERROR, - ALD_BAD_ARCHIVE_ERROR, - ALD_MAX_ERROR -}; - -enum { - ALD_MMAP = 1 -}; - struct ald_archive { - bool mmapped; + struct archive ar; int nr_files; struct { uint8_t *data; @@ -57,14 +47,6 @@ struct ald_archive { int *fileptr[ALD_FILEMAX]; }; -struct archive_data { - size_t size; - uint8_t *data; - uint8_t *data_raw; - char *name; - struct ald_archive *archive; -}; - enum { ALDFILE_BGM, ALDFILE_CG, @@ -72,36 +54,11 @@ enum { ALDFILETYPE_MAX }; -struct ald_archive *ald[ALDFILETYPE_MAX]; - -/* - * Returns a human readable description of an error. - */ -const char *ald_strerror(int error); +struct archive *ald[ALDFILETYPE_MAX]; /* * Open an ALD archive. */ -struct ald_archive *ald_open(char **files, int count, int flags, int *error); - -/* - * Check if data exists in an ALD archive. - */ -bool ald_data_exists(struct ald_archive *ar, int no); - -/* - * Retrieve a piece of data from an ALD archive. - */ -struct archive_data *ald_get(struct ald_archive *archive, int no); - -/* - * Free an ald_data structure returned by `ald_get`. - */ -void ald_free_data(struct archive_data *data); - -/* - * Free an ald_archive structure returned by `ald_open`. - */ -void ald_free_archive(struct ald_archive *ar); +struct archive *ald_open(char **files, int count, int flags, int *error); #endif /* SYSTEM4_ALD_H */ diff --git a/include/system4/archive.h b/include/system4/archive.h new file mode 100644 index 0000000..f061928 --- /dev/null +++ b/include/system4/archive.h @@ -0,0 +1,92 @@ +/* Copyright (C) 2019 Nunuhara Cabbage + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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 . + */ + +#ifndef SYSTEM4_ARCHIVE_H +#define SYSTEM4_ARCHIVE_H + +#include +#include +#include + +enum ald_error { + ARCHIVE_SUCCESS, + ARCHIVE_FILE_ERROR, + ARCHIVE_BAD_ARCHIVE_ERROR, + ARCHIVE_MAX_ERROR +}; + +enum { + ARCHIVE_MMAP = 1 +}; + +struct archive { + bool mmapped; + struct archive_ops *ops; +}; + +struct archive_ops { + bool (*exists)(struct archive *ar, int no); + struct archive_data *(*get)(struct archive *ar, int no); + void (*free_data)(struct archive_data *data); + void (*free)(struct archive *ar); +}; + +struct archive_data { + size_t size; + uint8_t *data; + uint8_t *data_raw; + char *name; + struct archive *archive; +}; + +/* + * Returns a human readable description of an error. + */ +const char *archive_strerror(int error); + +/* + * Check if data exists in an archive. + */ +static inline bool archive_exists(struct archive *ar, int no) +{ + return ar->ops->exists(ar, no); +} + +/* + * Retrieve a piece of data from an ALD archive. + */ +static inline struct archive_data *archive_get(struct archive *ar, int no) +{ + return ar->ops->get(ar, no); +} + +/* + * Free an archive_data structure returned by `archive_get`. + */ +static inline void archive_free_data(struct archive_data *data) +{ + data->archive->ops->free_data(data); +} + +/* + * Free an ald_archive structure returned by `ald_open`. + */ +static inline void archive_free(struct archive *ar) +{ + ar->ops->free(ar); +} + +#endif /* SYSTEM4_ARCHIVE_H */ diff --git a/include/system4/cg.h b/include/system4/cg.h index 9874991..cb718f9 100644 --- a/include/system4/cg.h +++ b/include/system4/cg.h @@ -22,7 +22,7 @@ #include #include -struct ald_archive; +struct archive; /* * Available CG formats @@ -53,8 +53,8 @@ struct cg { void *pixels; }; -bool cg_get_metrics(struct ald_archive *ar, int no, struct cg_metrics *dst); -struct cg *cg_load(struct ald_archive *ar, int no); +bool cg_get_metrics(struct archive *ar, int no, struct cg_metrics *dst); +struct cg *cg_load(struct archive *ar, int no); void cg_free(struct cg *cg); #endif /* SYSTEM4_CG_H */ diff --git a/src/ald.c b/src/ald.c index 72d3dd1..d06c47f 100644 --- a/src/ald.c +++ b/src/ald.c @@ -36,19 +36,17 @@ #include #endif -static const char *errtab[ALD_MAX_ERROR] = { - [ALD_SUCCESS] = "Success", - [ALD_FILE_ERROR] = "Error opening ALD file", - [ALD_BAD_ARCHIVE_ERROR] = "Invalid ALD file" -}; +static bool ald_exists(struct archive *ar, int no); +static struct archive_data *ald_get(struct archive *ar, int no); +static void ald_free_data(struct archive_data *data); +static void ald_free(struct archive *ar); -/* Get a message describing an error. */ -const char *ald_strerror(int error) -{ - if (error < ALD_MAX_ERROR) - return errtab[error]; - return "Invalid error number"; -} +struct archive_ops ald_archive_ops = { + .exists = ald_exists, + .get = ald_get, + .free_data = ald_free_data, + .free = ald_free, +}; /* Get the size of a file in bytes. */ static long get_file_size(FILE *fp) @@ -188,25 +186,26 @@ static int _ald_get(struct ald_archive *ar, int no, int *disk_out, int *dataptr_ return dataptr2 - dataptr; } -bool ald_data_exists(struct ald_archive *ar, int no) +static bool ald_exists(struct archive *ar, int no) { int disk, dataptr; - return ar && !!_ald_get(ar, no, &disk, &dataptr); + return ar && !!_ald_get((struct ald_archive*)ar, no, &disk, &dataptr); } /* Get a piece of data from an ALD archive. */ -struct archive_data *ald_get(struct ald_archive *ar, int no) +struct archive_data *ald_get(struct archive *_ar, int no) { - if (!ar) + if (!_ar) return NULL; uint8_t *data; struct archive_data *dfile; int disk, dataptr, ptr, size; + struct ald_archive *ar = (struct ald_archive*)_ar; int readsize = _ald_get(ar, no, &disk, &dataptr); // get data top - if (ar->mmapped) { + if (ar->ar.mmapped) { data = ar->files[disk].data + dataptr; } else { //int readsize = dataptr2 - dataptr; @@ -228,28 +227,31 @@ struct archive_data *ald_get(struct ald_archive *ar, int no) dfile->data = data + ptr; dfile->size = size; dfile->name = strdup((char*)data + 16); - dfile->archive = ar; + dfile->archive = &ar->ar; return dfile; } /* Free an ald_data strcture returned by `ald_get`. */ -void ald_free_data(struct archive_data *data) +static void ald_free_data(struct archive_data *data) { if (!data) return; - if (!((struct ald_archive*)data->archive)->mmapped) + if (!data->archive->mmapped) free(data->data); free(data->name); free(data); } /* Free an ald_archive structure returned by `ald_open`. */ -void ald_free_archive(struct ald_archive *ar) +static void ald_free(struct archive *_ar) { - if (!ar) + if (!_ar) return; + + struct ald_archive *ar = (struct ald_archive*)_ar; + // unmap mmap files - if (ar->mmapped) { + if (ar->ar.mmapped) { for (int i = 0; i < ALD_FILEMAX; i++) { if (ar->files[i].data) munmap(ar->files[i].data, ar->files[i].size); @@ -259,7 +261,7 @@ void ald_free_archive(struct ald_archive *ar) } /* Open an ALD archive, optionally memory-mapping it. */ -struct ald_archive *ald_open(char **files, int count, int flags, int *error) +struct archive *ald_open(char **files, int count, int flags, int *error) { FILE *fp; long filesize; @@ -267,7 +269,7 @@ struct ald_archive *ald_open(char **files, int count, int flags, int *error) bool gotmap = false; #ifdef _WIN32 - flags &= ~ALD_MMAP; + flags &= ~ARCHIVE_MMAP; #endif for (int i = 0; i < count; i++) { @@ -275,12 +277,12 @@ struct ald_archive *ald_open(char **files, int count, int flags, int *error) if (!files[i]) continue; if (!(fp = fopen(files[i], "r"))) { - *error = ALD_FILE_ERROR; + *error = ARCHIVE_FILE_ERROR; goto exit_err; } // check if it's a valid archive if (!file_check(fp)) { - *error = ALD_BAD_ARCHIVE_ERROR; + *error = ARCHIVE_BAD_ARCHIVE_ERROR; fclose(fp); goto exit_err; } @@ -297,16 +299,16 @@ struct ald_archive *ald_open(char **files, int count, int flags, int *error) ar->files[i].name = strdup(files[i]); // close fclose(fp); - if (flags & ALD_MMAP) { + if (flags & ARCHIVE_MMAP) { int fd; if (0 > (fd = open(files[i], O_RDONLY))) { - *error = ALD_FILE_ERROR; + *error = ARCHIVE_FILE_ERROR; goto exit_err; } ar->files[i].data = mmap(0, filesize, PROT_READ, MAP_SHARED, fd, 0); close(fd); if (ar->files[i].data == MAP_FAILED) { - *error = ALD_FILE_ERROR; + *error = ARCHIVE_FILE_ERROR; goto exit_err; } ar->files[i].size = filesize; @@ -318,10 +320,12 @@ struct ald_archive *ald_open(char **files, int count, int flags, int *error) continue; c++; } - ar->mmapped = flags & ALD_MMAP; + ar->ar.mmapped = flags & ARCHIVE_MMAP; ar->nr_files = count; - return ar; + ar->ar.ops = &ald_archive_ops; + return &ar->ar; exit_err: free(ar); return NULL; } + diff --git a/src/archive.c b/src/archive.c new file mode 100644 index 0000000..2c62401 --- /dev/null +++ b/src/archive.c @@ -0,0 +1,32 @@ +/* Copyright (C) 2019 Nunuhara Cabbage + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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 "system4.h" +#include "system4/ald.h" + +static const char *errtab[ARCHIVE_MAX_ERROR] = { + [ARCHIVE_SUCCESS] = "Success", + [ARCHIVE_FILE_ERROR] = "Error opening ALD file", + [ARCHIVE_BAD_ARCHIVE_ERROR] = "Invalid ALD file" +}; + +/* Get a message describing an error. */ +const char *archive_strerror(int error) +{ + if (error < ARCHIVE_MAX_ERROR) + return errtab[error]; + return "Invalid error number"; +} diff --git a/src/audio.c b/src/audio.c index eb32826..ea7ba3f 100644 --- a/src/audio.c +++ b/src/audio.c @@ -101,7 +101,7 @@ static int audio_type_to_archive_type(enum audio_type type) bool audio_exists(enum audio_type type, int no) { int archive = audio_type_to_archive_type(type); - return ald[archive] && ald_data_exists(ald[archive], no); + return ald[archive] && archive_exists(ald[archive], no); } static Mix_Chunk *load_chunk(enum audio_type type, int no) @@ -109,13 +109,13 @@ static Mix_Chunk *load_chunk(enum audio_type type, int no) struct archive_data *dfile; int archive = audio_type_to_archive_type(type); - if (!(dfile = ald_get(ald[archive], no))) { + if (!(dfile = archive_get(ald[archive], no))) { WARNING("Failed to load %s %d", archive == ALDFILE_BGM ? "BGM" : "WAV", no); return NULL; } Mix_Chunk *chunk = Mix_LoadWAV_RW(SDL_RWFromConstMem(dfile->data, dfile->size), 1); - ald_free_data(dfile); + archive_free_data(dfile); if (!chunk) { WARNING("%s %d: not a valid audio file", archive == ALDFILE_BGM ? "BGM" : "WAV", no); diff --git a/src/cg.c b/src/cg.c index d06d0bd..0d793f5 100644 --- a/src/cg.c +++ b/src/cg.c @@ -18,7 +18,7 @@ #include #include #include "system4.h" -#include "system4/ald.h" +#include "system4/archive.h" #include "system4/cg.h" #include "system4/qnt.h" @@ -35,11 +35,11 @@ static enum cg_type check_cgformat(uint8_t *data) return ALCG_UNKNOWN; } -bool cg_get_metrics(struct ald_archive *ar, int no, struct cg_metrics *dst) +bool cg_get_metrics(struct archive *ar, int no, struct cg_metrics *dst) { struct archive_data *dfile; - if (!(dfile = ald_get(ar, no))) + if (!(dfile = archive_get(ar, no))) return false; switch (check_cgformat(dfile->data)) { @@ -48,10 +48,10 @@ bool cg_get_metrics(struct ald_archive *ar, int no, struct cg_metrics *dst) break; default: WARNING("Unknown CG type (CG %d)", no); - ald_free_data(dfile); + archive_free_data(dfile); return false; } - ald_free_data(dfile); + archive_free_data(dfile); return true; } @@ -72,13 +72,13 @@ void cg_free(struct cg *cg) * no: file no ( >= 0) * return: cg object(extracted) */ -struct cg *cg_load(struct ald_archive *ar, int no) +struct cg *cg_load(struct archive *ar, int no) { struct cg *cg; struct archive_data *dfile; int type; - if (!(dfile = ald_get(ar, no))) { + if (!(dfile = archive_get(ar, no))) { WARNING("Failed to load CG %d", no); return NULL; } @@ -104,7 +104,7 @@ struct cg *cg_load(struct ald_archive *ar, int no) } // ok to free - ald_free_data(dfile); + archive_free_data(dfile); if (cg->pixels) return cg; diff --git a/src/hll/SACT2.c b/src/hll/SACT2.c index 8030194..73d321b 100644 --- a/src/hll/SACT2.c +++ b/src/hll/SACT2.c @@ -114,7 +114,7 @@ int sact_Key_IsDown(int keycode) int sact_CG_IsExist(int cg_no) { - return ald[ALDFILE_CG] && ald_data_exists(ald[ALDFILE_CG], cg_no - 1); + return ald[ALDFILE_CG] && archive_exists(ald[ALDFILE_CG], cg_no - 1); } int sact_Music_IsExist(int n) diff --git a/src/meson.build b/src/meson.build index a8901dc..aa40788 100644 --- a/src/meson.build +++ b/src/meson.build @@ -1,6 +1,7 @@ # sources for libsys4.a system4 = ['ain.c', 'ald.c', + 'archive.c', 'buffer.c', 'cg.c', 'ex.c', diff --git a/src/system4.c b/src/system4.c index bf28e57..38f6f65 100644 --- a/src/system4.c +++ b/src/system4.c @@ -75,10 +75,10 @@ static int ald_count[ALDFILETYPE_MAX]; void ald_init(int type, char **files, int count) { - int error = ALD_SUCCESS; - ald[type] = ald_open(files, count, ALD_MMAP, &error); + int error = ARCHIVE_SUCCESS; + ald[type] = ald_open(files, count, ARCHIVE_MMAP, &error); if (error) - ERROR("Failed to open ALD file: %s\n", ald_strerror(error)); + ERROR("Failed to open ALD file: %s\n", archive_strerror(error)); } static void init_gamedata_dir(const char *path)