From ac389b1af3b992b64fbdcc24d1143635da5ba76c Mon Sep 17 00:00:00 2001 From: NicknineTheEagle Date: Sun, 8 Nov 2020 22:42:57 +0300 Subject: [PATCH] Added TXTM format for specifying companion files --- src/meta/awb.c | 3 ++ src/meta/ea_eaac.c | 18 +++++++----- src/meta/ea_schl.c | 9 +++--- src/meta/xwb_xsb.h | 4 +++ src/streamfile.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++ src/streamfile.h | 4 +++ 6 files changed, 96 insertions(+), 12 deletions(-) diff --git a/src/meta/awb.c b/src/meta/awb.c index b0be134b..1b741acd 100644 --- a/src/meta/awb.c +++ b/src/meta/awb.c @@ -178,6 +178,9 @@ static void load_awb_name(STREAMFILE* sf, STREAMFILE* sf_acb, VGMSTREAM* vgmstre char filename[PATH_LIMIT]; int len_name, len_cmp; + /* try parsing TXTM if present */ + sf_acb = read_filemap_file(sf_acb, 0); + if (sf_acb) return sf_acb; /* try (name).awb + (name).awb */ sf_acb = open_streamfile_by_ext(sf, "acb"); diff --git a/src/meta/ea_eaac.c b/src/meta/ea_eaac.c index 95a1f1a7..cd7ac390 100644 --- a/src/meta/ea_eaac.c +++ b/src/meta/ea_eaac.c @@ -526,16 +526,20 @@ static STREAMFILE *open_mapfile_pair(STREAMFILE* sf, int track, int num_tracks) "trick_alps0.mus," "trick_lhotse0.mus"} }; - STREAMFILE *musFile = NULL; + STREAMFILE *sf_mus = NULL; char file_name[PATH_LIMIT]; int pair_count = (sizeof(mapfile_pairs) / sizeof(mapfile_pairs[0])); int i, j; size_t file_len, map_len; + /* try parsing TXTM if present */ + sf_mus = read_filemap_file(sf, track); + if (sf_mus) return sf_mus; + /* if loading the first track, try opening MUS with the same name first (most common scenario) */ if (track == 0) { - musFile = open_streamfile_by_ext(sf, "mus"); - if (musFile) return musFile; + sf_mus = open_streamfile_by_ext(sf, "mus"); + if (sf_mus) return sf_mus; } get_streamfile_filename(sf, file_name, PATH_LIMIT); @@ -579,8 +583,8 @@ static STREAMFILE *open_mapfile_pair(STREAMFILE* sf, int track, int num_tracks) strncpy(file_name, pch, PATH_LIMIT - 1); } - musFile = open_streamfile_by_filename(sf, file_name); - if (musFile) return musFile; + sf_mus = open_streamfile_by_filename(sf, file_name); + if (sf_mus) return sf_mus; get_streamfile_filename(sf, file_name, PATH_LIMIT); /* reset for next loop */ } @@ -591,8 +595,8 @@ static STREAMFILE *open_mapfile_pair(STREAMFILE* sf, int track, int num_tracks) char *mod_name = strchr(file_name, '+'); if (mod_name) { mod_name[0] = '\0'; - musFile = open_streamfile_by_filename(sf, file_name); - if (musFile) return musFile; + sf_mus = open_streamfile_by_filename(sf, file_name); + if (sf_mus) return sf_mus; } } diff --git a/src/meta/ea_schl.c b/src/meta/ea_schl.c index 378795b6..565afc52 100644 --- a/src/meta/ea_schl.c +++ b/src/meta/ea_schl.c @@ -636,11 +636,6 @@ static STREAMFILE* open_mapfile_pair(STREAMFILE* sf, int track, int num_tracks) {"SSX4FE.mpf", "TrackFE.mus"}, /* SSX On Tour */ {"SSX4Path.mpf", "Track.mus"}, /* SSX On Tour */ {"SSX4.mpf", "moments0.mus,main.mus,load_loop0.mus"}, /* SSX Blur */ - {"willow.mpf", "willow.mus,willow_o.mus"}, /* Harry Potter and the Chamber of Secrets */ - {"exterior.mpf", "exterior.mus,ext_o.mus"}, /* Harry Potter and the Chamber of Secrets */ - {"Peak1Amb.mpf", "Peak1_Strm.mus,Peak1_Ovr0.mus"}, /* SSX 3 */ - {"Peak2Amb.mpf", "Peak2_Strm.mus,Peak2_Ovr0.mus"}, - {"Peak3Amb.mpf", "Peak3_Strm.mus,Peak3_Ovr0.mus"}, {"*.mpf", "*_main.mus"}, /* 007 - Everything or Nothing */ /* TODO: need better wildcard support * NSF2: @@ -663,6 +658,10 @@ static STREAMFILE* open_mapfile_pair(STREAMFILE* sf, int track, int num_tracks) int i, j; size_t file_len, map_len; + /* try parsing TXTM if present */ + sf_mus = read_filemap_file(sf, track); + if (sf_mus) return sf_mus; + /* if loading the first track, try opening MUS with the same name first (most common scenario) */ if (track == 0) { sf_mus = open_streamfile_by_ext(sf, "mus"); diff --git a/src/meta/xwb_xsb.h b/src/meta/xwb_xsb.h index c4f56cd1..b68e3059 100644 --- a/src/meta/xwb_xsb.h +++ b/src/meta/xwb_xsb.h @@ -905,6 +905,10 @@ static STREAMFILE * open_xsb_filename_pair(STREAMFILE *streamXwb) { char temp_filename[PATH_LIMIT]; int target_len; + /* try parsing TXTM if present */ + streamXsb = read_filemap_file(streamXwb, 0); + if (streamXsb) return streamXsb; + /* try names in external .xsb, using a bunch of possible name pairs */ get_streamfile_filename(streamXwb,target_filename,PATH_LIMIT); target_len = strlen(target_filename); diff --git a/src/streamfile.c b/src/streamfile.c index 09a7e5e3..9e7cf004 100644 --- a/src/streamfile.c +++ b/src/streamfile.c @@ -1122,6 +1122,76 @@ fail: return 0; } +STREAMFILE *read_filemap_file(STREAMFILE *sf, int file_num) { + char filename[PATH_LIMIT]; + off_t txt_offset, file_size; + STREAMFILE *sf_map = NULL; + + sf_map = open_streamfile_by_filename(sf, ".txtm"); + if (!sf_map) goto fail; + + get_streamfile_filename(sf, filename, sizeof(filename)); + + txt_offset = 0x00; + file_size = get_streamfile_size(sf_map); + + /* skip BOM if needed */ + if ((uint16_t)read_16bitLE(0x00, sf_map) == 0xFFFE || + (uint16_t)read_16bitLE(0x00, sf_map) == 0xFEFF) { + txt_offset = 0x02; + } else if (((uint32_t)read_32bitBE(0x00, sf_map) & 0xFFFFFF00) == 0xEFBBBF00) { + txt_offset = 0x03; + } + + /* read lines and find target filename, format is (filename): value1, ... valueN */ + while (txt_offset < file_size) { + char line[0x2000]; + char key[PATH_LIMIT] = { 0 }, val[0x2000] = { 0 }; + int ok, bytes_read, line_ok; + + bytes_read = read_line(line, sizeof(line), txt_offset, sf_map, &line_ok); + if (!line_ok) goto fail; + + txt_offset += bytes_read; + + /* get key/val (ignores lead spaces, stops at space/comment/separator) */ + ok = sscanf(line, " %[^ \t#:] : %[^\t#\r\n] ", key, val); + if (ok != 2) { /* ignore line if no key=val (comment or garbage) */ + continue; + } + + if (strcmp(key, filename) == 0) { + int n; + char subval[PATH_LIMIT]; + const char *current = val; + int i; + + for (i = 0; i <= file_num; i++) { + if (current[0] == '\0') + goto fail; + + ok = sscanf(current, " %[^\t#\r\n,]%n ", subval, &n); + if (ok != 1) + goto fail; + + if (i == file_num) + { + close_streamfile(sf_map); + return open_streamfile_by_filename(sf, subval); + } + + current += n; + if (current[0] == ',') + current++; + } + } + } + +fail: + close_streamfile(sf_map); + return NULL; +} + void fix_dir_separators(char * filename) { char c; int i = 0; diff --git a/src/streamfile.h b/src/streamfile.h index 72b7d343..83d68417 100644 --- a/src/streamfile.h +++ b/src/streamfile.h @@ -345,6 +345,10 @@ size_t read_string_utf16be(char* buf, size_t buf_size, off_t offset, STREAMFILE* * returns size of key if found and copied */ size_t read_key_file(uint8_t* buf, size_t buf_size, STREAMFILE* sf); +/* Opens .txtm file containing file:companion file(-s) mappings and tries to see if there's a match + * then loads the associated companion file if one is found */ +STREAMFILE *read_filemap_file(STREAMFILE *sf, int file_num); + /* hack to allow relative paths in various OSs */ void fix_dir_separators(char* filename);