diff --git a/game_compatibility.md b/game_compatibility.md index b1665e3..a0a0135 100644 --- a/game_compatibility.md +++ b/game_compatibility.md @@ -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 | diff --git a/src/dri.c b/src/dri.c index c9ce490..e25fe29 100644 --- a/src/dri.c +++ b/src/dri.c @@ -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]; diff --git a/src/dri.h b/src/dri.h index 2ac6d4c..7c4304f 100644 --- a/src/dri.h +++ b/src/dri.h @@ -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;