mirror of
https://github.com/kichikuou/xsystem35-sdl2.git
synced 2026-10-07 22:28:01 +03:00
Read link table only from first ALD volume
This fixes https://github.com/kichikuou/xsystem35-sdl2/issues/45. The behavior when the contents of link table differ between ALD volumes is different between System 3.8 and System 3.9, and System 3.9 uses the link table of the first volume. The MangaGamer version of Rance 5D depends on this behavior. As far as I know, the only game that depends on the System 3.8 behavior is Child Assassin (in Alice CD 2.50). Considering the additional complexity, we do not implement switching to the old behavior.
This commit is contained in:
@@ -76,7 +76,7 @@ Game Compatibility
|
||||
| マスカレイド | Supported | From アリスCD |
|
||||
| キャロル ~聖なる鐘が響く夜~ | Supported | From アリスCD, Online match is not supported |
|
||||
| できるかなー? | Supported | From アリスCD |
|
||||
| Child Assassin | Supported | From アリスCD |
|
||||
| Child Assassin | Unsupported | From アリスCD |
|
||||
| Klavier | Supported | From アリスCD |
|
||||
| 弱肉狂食 | Supported | From アリスCD |
|
||||
| 眼鏡大戦2 | Supported | From アリスCD |
|
||||
|
||||
@@ -30,50 +30,48 @@
|
||||
#include "LittleEndian.h"
|
||||
#include "dri.h"
|
||||
|
||||
static bool read_index(int disk, drifiles *d, FILE *fp) {
|
||||
static bool read_index(int volume, drifiles *d, FILE *fp) {
|
||||
fseek(fp, 0L, SEEK_END);
|
||||
int filesize = ftell(fp);
|
||||
|
||||
// Get ptrsize and mapsize
|
||||
// Get the size of offsets table and link table.
|
||||
uint8_t hdr[6];
|
||||
fseek(fp, 0L, SEEK_SET);
|
||||
if (fread(hdr, 6, 1, fp) != 1)
|
||||
return false;
|
||||
int ptrsize = LittleEndian_get3B(hdr, 0) << 8;
|
||||
int mapsize = (LittleEndian_get3B(hdr, 3) << 8) - ptrsize;
|
||||
if (ptrsize <= 0 || mapsize <= 0 || ptrsize + mapsize > filesize)
|
||||
int ofssize = LittleEndian_get3B(hdr, 0) << 8;
|
||||
int linksize = (LittleEndian_get3B(hdr, 3) << 8) - ofssize;
|
||||
if (ofssize <= 0 || linksize <= 0 || ofssize + linksize > filesize)
|
||||
return false;
|
||||
|
||||
// Read the pointer table and the link table
|
||||
uint8_t *ptbl = malloc(ptrsize + mapsize);
|
||||
memcpy(ptbl, hdr, 6);
|
||||
if (fread(ptbl + 6, ptrsize + mapsize - 6, 1, fp) != 1) {
|
||||
free(ptbl);
|
||||
// Read the link table. In System 3.9, only the first volume's link table is
|
||||
// valid. It's different in System 3.8 and earlier, and games that depend
|
||||
// on the old behavior (e.g. Child Assassin in Alice CD 2.50) won't work.
|
||||
if (!d->link) {
|
||||
d->nr_files = linksize / 3;
|
||||
d->link = calloc(1, linksize);
|
||||
d->offset = calloc(sizeof(uint32_t), d->nr_files);
|
||||
fseek(fp, ofssize, SEEK_SET);
|
||||
if (fread(d->link, linksize, 1, fp) != 1)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the offsets table.
|
||||
uint8_t *otbl = malloc(ofssize);
|
||||
fseek(fp, 0L, SEEK_SET);
|
||||
if (fread(otbl, ofssize, 1, fp) != 1) {
|
||||
free(otbl);
|
||||
return false;
|
||||
}
|
||||
uint8_t *ltbl = ptbl + ptrsize;
|
||||
|
||||
// (Re)allocate the index buffers
|
||||
int nr_files = mapsize / 3;
|
||||
if (d->nr_files < nr_files) {
|
||||
d->disk = realloc(d->disk, nr_files);
|
||||
d->offset = realloc(d->offset, sizeof(uint32_t) * nr_files);
|
||||
memset(d->disk + d->nr_files, 0, nr_files - d->nr_files);
|
||||
memset(d->offset + d->nr_files, 0, sizeof(uint32_t) * (nr_files - d->nr_files));
|
||||
d->nr_files = nr_files;
|
||||
}
|
||||
|
||||
// Parse the index
|
||||
for (int i = 0; i < nr_files; i++) {
|
||||
if (disk != ltbl[i * 3] - 1)
|
||||
for (int i = 0; i < d->nr_files; i++) {
|
||||
if (d->link[i * 3] != volume)
|
||||
continue;
|
||||
if (d->maxno < i)
|
||||
d->maxno = i;
|
||||
d->disk[i] = ltbl[i * 3];
|
||||
int ptr = LittleEndian_getW(ltbl, i * 3 + 1);
|
||||
d->offset[i] = LittleEndian_get3B(ptbl, ptr * 3) << 8;
|
||||
int offset_index = LittleEndian_getW(d->link, i * 3 + 1);
|
||||
d->offset[i] = LittleEndian_get3B(otbl, offset_index * 3) << 8;
|
||||
}
|
||||
free(ptbl);
|
||||
free(otbl);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -90,7 +88,7 @@ drifiles *dri_init(const char **file, int cnt, boolean use_mmap) {
|
||||
FILE *fp = fopen(file[i], "rb");
|
||||
if (!fp)
|
||||
SYSERROR("%s: %s", file[i], strerror(errno));
|
||||
if (!read_index(i, d, fp)) {
|
||||
if (!read_index(i + 1, d, fp)) {
|
||||
// Only errors in *A.ALD are fatal, because some games have
|
||||
// dummy (invalid) *[B-Z].ALD files.
|
||||
if (i == 0)
|
||||
@@ -117,18 +115,18 @@ drifiles *dri_init(const char **file, int cnt, boolean use_mmap) {
|
||||
}
|
||||
|
||||
dridata *dri_getdata(drifiles *d, int no) {
|
||||
if (no < 0 || no >= d->nr_files || !d->disk[no] || !d->offset[no])
|
||||
if (no < 0 || no >= d->nr_files || !d->link[no * 3] || !d->offset[no])
|
||||
return NULL;
|
||||
int disk = d->disk[no] - 1;
|
||||
int volume = d->link[no * 3];
|
||||
|
||||
uint8_t *data;
|
||||
int ptr, size;
|
||||
if (d->mmapped) {
|
||||
data = d->mmap[disk]->addr + d->offset[no];
|
||||
data = d->mmap[volume - 1]->addr + d->offset[no];
|
||||
ptr = LittleEndian_getDW(data, 0);
|
||||
size = LittleEndian_getDW(data, 4);
|
||||
} else {
|
||||
FILE *fp = fopen(d->fnames[disk], "rb");
|
||||
FILE *fp = fopen(d->fnames[volume - 1], "rb");
|
||||
if (!fp)
|
||||
return NULL;
|
||||
uint8_t entry_header[8];
|
||||
|
||||
@@ -35,7 +35,7 @@ struct _drifiles {
|
||||
char *fnames[DRIFILEMAX];
|
||||
int nr_files; // upper limit on how many files could be referenced by this archive
|
||||
int maxno;
|
||||
uint8_t *disk; // file numbers
|
||||
uint8_t *link; // link table
|
||||
uint32_t *offset; // offsets in file
|
||||
};
|
||||
typedef struct _drifiles drifiles;
|
||||
|
||||
Reference in New Issue
Block a user