Use abstract archive interface for ALD files

In preparation for AFA support in libsystem4.
This commit is contained in:
Nunuhara Cabbage
2020-02-23 18:49:51 -08:00
parent 6e29fee7ed
commit be1b5ecc8f
10 changed files with 183 additions and 97 deletions
+4 -47
View File
@@ -24,23 +24,13 @@
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#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 */
+92
View File
@@ -0,0 +1,92 @@
/* Copyright (C) 2019 Nunuhara Cabbage <nunuhara@haniwa.technology>
*
* 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 <http://gnu.org/licenses/>.
*/
#ifndef SYSTEM4_ARCHIVE_H
#define SYSTEM4_ARCHIVE_H
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
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 */
+3 -3
View File
@@ -22,7 +22,7 @@
#include <stdbool.h>
#include <stdint.h>
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 */
+36 -32
View File
@@ -36,19 +36,17 @@
#include <sys/mman.h>
#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;
}
+32
View File
@@ -0,0 +1,32 @@
/* Copyright (C) 2019 Nunuhara Cabbage <nunuhara@haniwa.technology>
*
* 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 <http://gnu.org/licenses/>.
*/
#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";
}
+3 -3
View File
@@ -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);
+8 -8
View File
@@ -18,7 +18,7 @@
#include <stdint.h>
#include <stdlib.h>
#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;
+1 -1
View File
@@ -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)
+1
View File
@@ -1,6 +1,7 @@
# sources for libsys4.a
system4 = ['ain.c',
'ald.c',
'archive.c',
'buffer.c',
'cg.c',
'ex.c',
+3 -3
View File
@@ -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)