diff --git a/Frameworks/vgmstream/libvgmstream.xcodeproj/project.pbxproj b/Frameworks/vgmstream/libvgmstream.xcodeproj/project.pbxproj index 49871976d..9a45b9fb1 100644 --- a/Frameworks/vgmstream/libvgmstream.xcodeproj/project.pbxproj +++ b/Frameworks/vgmstream/libvgmstream.xcodeproj/project.pbxproj @@ -86,6 +86,7 @@ 8313E3E71902021800B4B6F1 /* mpg123.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8313E3431901FBDD00B4B6F1 /* mpg123.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; 8315958720FEC832007002F0 /* asf_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 8315958320FEC831007002F0 /* asf_decoder.c */; }; 8315958920FEC83F007002F0 /* asf.c in Sources */ = {isa = PBXBuildFile; fileRef = 8315958820FEC83F007002F0 /* asf.c */; }; + 8317C24C26982CC1007DD0B8 /* sspr.c in Sources */ = {isa = PBXBuildFile; fileRef = 8317C24826982CC1007DD0B8 /* sspr.c */; }; 831BA6181EAC61A500CF89B0 /* adx.c in Sources */ = {isa = PBXBuildFile; fileRef = 831BA60E1EAC61A500CF89B0 /* adx.c */; }; 831BA6191EAC61A500CF89B0 /* ogl.c in Sources */ = {isa = PBXBuildFile; fileRef = 831BA60F1EAC61A500CF89B0 /* ogl.c */; }; 831BA61A1EAC61A500CF89B0 /* ps2_vds_vdm.c in Sources */ = {isa = PBXBuildFile; fileRef = 831BA6101EAC61A500CF89B0 /* ps2_vds_vdm.c */; }; @@ -878,6 +879,7 @@ 8313E33D1901FBDC00B4B6F1 /* mpg123.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = mpg123.xcodeproj; path = ../mpg123/mpg123.xcodeproj; sourceTree = ""; }; 8315958320FEC831007002F0 /* asf_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = asf_decoder.c; sourceTree = ""; }; 8315958820FEC83F007002F0 /* asf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = asf.c; sourceTree = ""; }; + 8317C24826982CC1007DD0B8 /* sspr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sspr.c; sourceTree = ""; }; 831BA60E1EAC61A500CF89B0 /* adx.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = adx.c; sourceTree = ""; }; 831BA60F1EAC61A500CF89B0 /* ogl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ogl.c; sourceTree = ""; }; 831BA6101EAC61A500CF89B0 /* ps2_vds_vdm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_vds_vdm.c; sourceTree = ""; }; @@ -2098,6 +2100,7 @@ 836F6EF418BDC2190095E648 /* sqex_scd.c */, 837CEAF023487F2C00E62A4A /* sqex_sead_streamfile.h */, 83A21F84201D8981000F04B9 /* sqex_sead.c */, + 8317C24826982CC1007DD0B8 /* sspr.c */, 8306B0C12098458C000302D4 /* sthd.c */, 83AA5D231F6E2F9C0020821C /* stm.c */, 836F6EF618BDC2190095E648 /* str_asr.c */, @@ -2932,6 +2935,7 @@ 836F6F2518BDC2190095E648 /* g721_decoder.c in Sources */, 836F6FE818BDC2190095E648 /* ps2_mic.c in Sources */, 836F6F3C18BDC2190095E648 /* xa_decoder.c in Sources */, + 8317C24C26982CC1007DD0B8 /* sspr.c in Sources */, 832BF82521E0514B006F50F1 /* ogg_opus.c in Sources */, 83709E091ECBC1A4005C03D3 /* ta_aac.c in Sources */, 836F6F9118BDC2190095E648 /* ios_psnd.c in Sources */, diff --git a/Frameworks/vgmstream/vgmstream/src/coding/psx_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/psx_decoder.c index f4bb7e438..70d004c72 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/psx_decoder.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/psx_decoder.c @@ -184,7 +184,7 @@ void decode_psx_configurable(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int cha } /* PS-ADPCM from Pivotal games, exactly like psx_cfg but with float math (reverse engineered from the exe) */ -void decode_psx_pivotal(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int frame_size) { +void decode_psx_pivotal(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int frame_size) { uint8_t frame[0x50] = {0}; off_t frame_offset; int i, frames_in, sample_count = 0; @@ -250,7 +250,7 @@ void decode_psx_pivotal(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channe * - 0x7 (0111): End marker and don't decode * - 0x8+(1NNN): Not valid */ -static int ps_find_loop_offsets_internal(STREAMFILE *sf, off_t start_offset, size_t data_size, int channels, size_t interleave, int32_t * p_loop_start, int32_t * p_loop_end, int config) { +static int ps_find_loop_offsets_internal(STREAMFILE* sf, off_t start_offset, size_t data_size, int channels, size_t interleave, int32_t * p_loop_start, int32_t * p_loop_end, int config) { int num_samples = 0, loop_start = 0, loop_end = 0; int loop_start_found = 0, loop_end_found = 0; off_t offset = start_offset; @@ -303,6 +303,7 @@ static int ps_find_loop_offsets_internal(STREAMFILE *sf, off_t start_offset, siz && buf[0] != 0x00 /* ignore blank frame */ && buf[0] != 0x0c /* ignore silent frame */ && buf[0] != 0x3c /* ignore some L-R tracks with different end flags */ + && buf[0] != 0x1c /* ignore some L-R tracks with different end flags */ ) { /* assume full loop with repeated frame header and null frame */ @@ -343,19 +344,22 @@ static int ps_find_loop_offsets_internal(STREAMFILE *sf, off_t start_offset, siz return 0; /* no loop */ } -int ps_find_loop_offsets(STREAMFILE *sf, off_t start_offset, size_t data_size, int channels, size_t interleave, int32_t *p_loop_start, int32_t *p_loop_end) { +int ps_find_loop_offsets(STREAMFILE* sf, off_t start_offset, size_t data_size, int channels, size_t interleave, int32_t* p_loop_start, int32_t* p_loop_end) { return ps_find_loop_offsets_internal(sf, start_offset, data_size, channels, interleave, p_loop_start, p_loop_end, 0); } -int ps_find_loop_offsets_full(STREAMFILE *sf, off_t start_offset, size_t data_size, int channels, size_t interleave, int32_t *p_loop_start, int32_t *p_loop_end) { +int ps_find_loop_offsets_full(STREAMFILE* sf, off_t start_offset, size_t data_size, int channels, size_t interleave, int32_t* p_loop_start, int32_t* p_loop_end) { return ps_find_loop_offsets_internal(sf, start_offset, data_size, channels, interleave, p_loop_start, p_loop_end, 1); } -size_t ps_find_padding(STREAMFILE *streamFile, off_t start_offset, size_t data_size, int channels, size_t interleave, int discard_empty) { - off_t min_offset, offset; +size_t ps_find_padding(STREAMFILE* sf, off_t start_offset, size_t data_size, int channels, size_t interleave, int discard_empty) { + off_t min_offset, offset, read_offset = 0; size_t frame_size = 0x10; size_t padding_size = 0; size_t interleave_consumed = 0; + uint8_t buf[0x8000]; + int buf_pos = 0; + int bytes; if (data_size == 0 || channels == 0 || (channels > 1 && interleave == 0)) @@ -374,12 +378,22 @@ size_t ps_find_padding(STREAMFILE *streamFile, off_t start_offset, size_t data_s uint8_t flag; int is_empty = 0; + /* read in chunks to optimize (less SF rebuffering since we go in reverse) */ + if (offset < read_offset || buf_pos <= 0) { + read_offset = offset - sizeof(buf); + if (read_offset < 0) + read_offset = 0; //? + bytes = read_streamfile(buf, read_offset, sizeof(buf), sf); + buf_pos = (bytes / frame_size * frame_size); + } + + buf_pos -= frame_size; offset -= frame_size; - f1 = read_32bitBE(offset+0x00,streamFile); - f2 = read_32bitBE(offset+0x04,streamFile); - f3 = read_32bitBE(offset+0x08,streamFile); - f4 = read_32bitBE(offset+0x0c,streamFile); + f1 = get_u32be(buf+buf_pos+0x00); + f2 = get_u32be(buf+buf_pos+0x04); + f3 = get_u32be(buf+buf_pos+0x08); + f4 = get_u32be(buf+buf_pos+0x0c); flag = (f1 >> 16) & 0xFF; if (f1 == 0 && f2 == 0 && f3 == 0 && f4 == 0) @@ -406,9 +420,11 @@ size_t ps_find_padding(STREAMFILE *streamFile, off_t start_offset, size_t data_s if (interleave_consumed == interleave) { interleave_consumed = 0; offset -= interleave * (channels - 1); + buf_pos -= interleave * (channels - 1); } } + //;VGM_LOG("PSX PAD: total size %x\n", padding_size); return padding_size; } @@ -424,14 +440,14 @@ size_t ps_cfg_bytes_to_samples(size_t bytes, size_t frame_size, int channels) { } /* test PS-ADPCM frames for correctness */ -int ps_check_format(STREAMFILE *streamFile, off_t offset, size_t max) { +int ps_check_format(STREAMFILE* sf, off_t offset, size_t max) { off_t max_offset = offset + max; - if (max_offset > get_streamfile_size(streamFile)) - max_offset = get_streamfile_size(streamFile); + if (max_offset > get_streamfile_size(sf)) + max_offset = get_streamfile_size(sf); while (offset < max_offset) { - uint8_t predictor = (read_8bit(offset+0x00,streamFile) >> 4) & 0x0f; - uint8_t flags = read_8bit(offset+0x01,streamFile); + uint8_t predictor = (read_8bit(offset+0x00,sf) >> 4) & 0x0f; + uint8_t flags = read_8bit(offset+0x01,sf); if (predictor > 5 || flags > 7) { return 0; diff --git a/Frameworks/vgmstream/vgmstream/src/formats.c b/Frameworks/vgmstream/vgmstream/src/formats.c index 511d5587a..0baa8965d 100644 --- a/Frameworks/vgmstream/vgmstream/src/formats.c +++ b/Frameworks/vgmstream/vgmstream/src/formats.c @@ -143,6 +143,7 @@ static const char* extension_list[] = { "cwav", "cxs", + "d2", //txth/reserved [Dodonpachi Dai-Ou-Jou (PS2)] "da", //"dat", //common "data", @@ -437,6 +438,7 @@ static const char* extension_list[] = { "sb6", "sb7", "sbk", + "sbin", "sbr", "sbv", "sm0", @@ -447,7 +449,6 @@ static const char* extension_list[] = { "sm5", "sm6", "sm7", - "sbin", "sc", "scd", "sch", @@ -490,6 +491,7 @@ static const char* extension_list[] = { "ss2", "ssd", //txth/reserved [Zack & Wiki (Wii)] "ssm", + "sspr", "sss", "ster", "sth", diff --git a/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h b/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h index 0700949e3..b1f3a8774 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h +++ b/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h @@ -407,6 +407,9 @@ static const hcakey_info hcakey_list[] = { /* maimai DX Splash (AC) */ {9170825592834449000}, // 7F4551499DF55E68 + /* Dragon Quest Tact (Android) */ + {3234477171400153310}, // 2CE32BD9B36A98DE + /* D4DJ Groovy Mix (Android) [base files] */ {393410674916959300}, // 0575ACECA945A444 /* D4DJ Groovy Mix (Android) [music_* files, per-song later mixed with subkey] */ diff --git a/Frameworks/vgmstream/vgmstream/src/meta/meta.h b/Frameworks/vgmstream/vgmstream/src/meta/meta.h index ce0f21c5c..c41216aec 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/meta.h +++ b/Frameworks/vgmstream/vgmstream/src/meta/meta.h @@ -949,4 +949,6 @@ VGMSTREAM* init_vgmstream_tac(STREAMFILE* sf); VGMSTREAM* init_vgmstream_ogv_3rdeye(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_sspr(STREAMFILE* sf); + #endif /*_META_H*/ diff --git a/Frameworks/vgmstream/vgmstream/src/meta/sspr.c b/Frameworks/vgmstream/vgmstream/src/meta/sspr.c new file mode 100644 index 000000000..f24e1623c --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/meta/sspr.c @@ -0,0 +1,55 @@ +#include "meta.h" +#include "../coding/coding.h" + +/* SSPR - Capcom container [Sengoku Basara 4 (PS3/PS4), Mega Man Zero ZX Legacy Collection (PS4)] */ +VGMSTREAM* init_vgmstream_sspr(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; + STREAMFILE* temp_sf = NULL; + uint32_t name_offset, subfile_offset, subfile_size, name_size; + int big_endian; + int total_subsongs, target_subsong = sf->stream_index; + char* extension; + uint32_t (*read_u32)(off_t,STREAMFILE*) = NULL; + + + /* checks */ + if (!check_extensions(sf,"sspr")) + goto fail; + if (!is_id32be(0x00,sf,"SSPR")) + goto fail; + + /* Simple (audio only) container used some Capcom games (common engine?). + * Some files come with a .stqr with unknown data (cues?). */ + + big_endian = guess_endianness32bit(0x04, sf); /* 0x01 (version?) */ + read_u32 = big_endian ? read_u32be : read_u32le; + + total_subsongs = read_u32(0x08,sf); + if (target_subsong == 0) target_subsong = 1; + if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail; + /* 0x0c: null */ + + name_offset = read_u32(0x10 + (target_subsong-1) * 0x10 + 0x00,sf); + subfile_offset = read_u32(0x10 + (target_subsong-1) * 0x10 + 0x04,sf); + name_size = read_u32(0x10 + (target_subsong-1) * 0x10 + 0x08,sf); + subfile_size = read_u32(0x10 + (target_subsong-1) * 0x10 + 0x0c,sf); + + extension = big_endian ? "at3" : "at9"; + + temp_sf = setup_subfile_streamfile(sf, subfile_offset, subfile_size, extension); + if (!temp_sf) goto fail; + + vgmstream = init_vgmstream_riff(temp_sf); + if (!vgmstream) goto fail; + + vgmstream->num_streams = total_subsongs; + read_string(vgmstream->stream_name,name_size+1, name_offset,sf); + + close_streamfile(temp_sf); + return vgmstream; + +fail: + close_streamfile(temp_sf); + close_vgmstream(vgmstream); + return NULL; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/txth.c b/Frameworks/vgmstream/vgmstream/src/meta/txth.c index 566c1c4fd..16ade7b49 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/txth.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/txth.c @@ -808,8 +808,7 @@ static int get_padding_size(txth_header* txth, int discard_empty); /* Simple text parser of "key = value" lines. * The code is meh and error handling not exactly the best. */ static int parse_txth(txth_header* txth) { - off_t txt_offset = 0x00; - off_t file_size = get_streamfile_size(txth->sf_text); + off_t txt_offset, file_size; /* setup txth defaults */ if (txth->sf_body) @@ -818,14 +817,8 @@ static int parse_txth(txth_header* txth) { if (txth->target_subsong == 0) txth->target_subsong = 1; - /* skip BOM if needed */ - if ((uint16_t)read_16bitLE(0x00, txth->sf_text) == 0xFFFE || - (uint16_t)read_16bitLE(0x00, txth->sf_text) == 0xFEFF) { - txt_offset = 0x02; - } - else if (((uint32_t)read_32bitBE(0x00, txth->sf_text) & 0xFFFFFF00) == 0xEFBBBF00) { - txt_offset = 0x03; - } + txt_offset = read_bom(txth->sf_text); + file_size = get_streamfile_size(txth->sf_text); /* read lines */ { @@ -1533,7 +1526,7 @@ static int read_name_table_keyval(txth_header* txth, const char* line, char* key /* try "(name): (val))" */ ok = sscanf(line, " %[^\t#:] : %[^\t#\r\n] ", key, val); if (ok == 2) { - ;VGM_LOG("TXTH: name %s get\n", key); + //;VGM_LOG("TXTH: name %s get\n", key); return 1; } @@ -1541,14 +1534,14 @@ static int read_name_table_keyval(txth_header* txth, const char* line, char* key key[0] = '\0'; ok = sscanf(line, " : %[^\t#\r\n] ", val); if (ok == 1) { - ;VGM_LOG("TXTH: default get\n"); + //;VGM_LOG("TXTH: default get\n"); return 1; } /* try "(name)#subsong: (val))" */ ok = sscanf(line, " %[^\t#:]#%i : %[^\t#\r\n] ", key, &subsong, val); if (ok == 3 && subsong == txth->target_subsong) { - VGM_LOG("TXTH: name %s + subsong %i get\n", key, subsong); + //;VGM_LOG("TXTH: name %s + subsong %i get\n", key, subsong); return 1; } @@ -1556,7 +1549,7 @@ static int read_name_table_keyval(txth_header* txth, const char* line, char* key key[0] = '\0'; ok = sscanf(line, " #%i: %[^\t#\r\n] ", &subsong, val); if (ok == 2 && subsong == txth->target_subsong) { - VGM_LOG("TXTH: default + subsong %i get\n", subsong); + //;VGM_LOG("TXTH: default + subsong %i get\n", subsong); return 1; } @@ -1596,18 +1589,9 @@ static int parse_name_table(txth_header* txth, char* name_list) { get_streamfile_basename(txth->sf_body, basename, sizeof(basename)); //;VGM_LOG("TXTH: names full=%s, file=%s, base=%s\n", fullname, filename, basename); - txt_offset = 0x00; + txt_offset = read_bom(sf_names); file_size = get_streamfile_size(sf_names); - /* skip BOM if needed */ - if ((uint16_t)read_16bitLE(0x00, sf_names) == 0xFFFE || - (uint16_t)read_16bitLE(0x00, sf_names) == 0xFEFF) { - txt_offset = 0x02; - } - else if (((uint32_t)read_32bitBE(0x00, sf_names) & 0xFFFFFF00) == 0xEFBBBF00) { - txt_offset = 0x03; - } - /* in case of repeated name tables */ memset(txth->name_values, 0, sizeof(txth->name_values)); txth->name_values_count = 0; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/txtp.c b/Frameworks/vgmstream/vgmstream/src/meta/txtp.c index e763162c6..450d8d076 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/txtp.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/txtp.c @@ -1887,8 +1887,7 @@ fail: static txtp_header* parse_txtp(STREAMFILE* sf) { txtp_header* txtp = NULL; - off_t txt_offset = 0x00; - off_t file_size = get_streamfile_size(sf); + off_t txt_offset, file_size; txtp = calloc(1,sizeof(txtp_header)); @@ -1897,16 +1896,8 @@ static txtp_header* parse_txtp(STREAMFILE* sf) { /* defaults */ txtp->is_segmented = 1; - - /* skip BOM if needed */ - if (file_size > 0 && - (read_u16le(0x00, sf) == 0xFFFE || read_u16le(0x00, sf) == 0xFEFF)) { - txt_offset = 0x02; - } - else if ((read_u32be(0x00, sf) & 0xFFFFFF00) == 0xEFBBBF00) { - txt_offset = 0x03; - } - + txt_offset = read_bom(sf); + file_size = get_streamfile_size(sf); /* read and parse lines */ { diff --git a/Frameworks/vgmstream/vgmstream/src/streamfile.c b/Frameworks/vgmstream/vgmstream/src/streamfile.c index 6c187e200..6c878ec3b 100644 --- a/Frameworks/vgmstream/vgmstream/src/streamfile.c +++ b/Frameworks/vgmstream/vgmstream/src/streamfile.c @@ -888,19 +888,25 @@ STREAMFILE* open_streamfile_by_ext(STREAMFILE* sf, const char* ext) { STREAMFILE* open_streamfile_by_filename(STREAMFILE* sf, const char* filename) { char fullname[PATH_LIMIT]; char partname[PATH_LIMIT]; - char *path, *name; + char *path, *name, *otherpath; if (!sf || !filename || !filename[0]) return NULL; sf->get_name(sf, fullname, sizeof(fullname)); //todo normalize separators in a better way, safeops, improve copying - path = strrchr(fullname,DIR_SEPARATOR); + + /* check for non-normalized paths first (ex. txth) */ + path = strrchr(fullname, '/'); + otherpath = strrchr(fullname, '\\'); + if (otherpath > path) + path = otherpath; + if (path) { path[1] = '\0'; /* remove name after separator */ strcpy(partname, filename); - fix_dir_separators(partname); + fix_dir_separators(partname); /* normalize to DIR_SEPARATOR */ /* normalize relative paths as don't work ok in some plugins */ if (partname[0] == '.' && partname[1] == DIR_SEPARATOR) { /* './name' */ @@ -996,6 +1002,19 @@ size_t read_line(char* buf, int buf_size, off_t offset, STREAMFILE* sf, int* p_l return i + extra_bytes; } +size_t read_bom(STREAMFILE* sf) { + if (read_u16le(0x00, sf) == 0xFFFE || + read_u16le(0x00, sf) == 0xFEFF) { + return 0x02; + } + + if ((read_u32be(0x00, sf) & 0xFFFFFF00) == 0xEFBBBF00) { + return 0x03; + } + + return 0x00; +} + size_t read_string(char* buf, size_t buf_size, off_t offset, STREAMFILE* sf) { size_t pos; @@ -1137,17 +1156,9 @@ STREAMFILE* read_filemap_file_pos(STREAMFILE* sf, int file_num, int* p_pos) { get_streamfile_filename(sf, filename, sizeof(filename)); - txt_offset = 0x00; + txt_offset = read_bom(sf_map); file_size = get_streamfile_size(sf_map); - /* skip BOM if needed */ - if (read_u16le(0x00, sf_map) == 0xFFFE || - read_u16le(0x00, sf_map) == 0xFEFF) { - txt_offset = 0x02; - } else if ((read_u32be(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]; diff --git a/Frameworks/vgmstream/vgmstream/src/streamfile.h b/Frameworks/vgmstream/vgmstream/src/streamfile.h index 148297af9..1ab12705f 100644 --- a/Frameworks/vgmstream/vgmstream/src/streamfile.h +++ b/Frameworks/vgmstream/vgmstream/src/streamfile.h @@ -355,6 +355,9 @@ static inline size_t align_size_to_block(size_t value, size_t block_align) { * p_line_ok is set to 1 if the complete line was read; pass NULL to ignore. */ size_t read_line(char* buf, int buf_size, off_t offset, STREAMFILE* sf, int* p_line_ok); +/* skip BOM if needed */ +size_t read_bom(STREAMFILE* sf); + /* reads a c-string (ANSI only), up to bufsize or NULL, returning size. buf is optional (works as get_string_size). */ size_t read_string(char* buf, size_t buf_size, off_t offset, STREAMFILE* sf); /* reads a UTF16 string... but actually only as ANSI (discards the upper byte) */ diff --git a/Frameworks/vgmstream/vgmstream/src/vgmstream.c b/Frameworks/vgmstream/vgmstream/src/vgmstream.c index 530856d0c..bd5f3209a 100644 --- a/Frameworks/vgmstream/vgmstream/src/vgmstream.c +++ b/Frameworks/vgmstream/vgmstream/src/vgmstream.c @@ -524,6 +524,7 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = { init_vgmstream_idsp_tose, init_vgmstream_dsp_kwa, init_vgmstream_ogv_3rdeye, + init_vgmstream_sspr, /* lowest priority metas (should go after all metas, and TXTH should go before raw formats) */ init_vgmstream_txth, /* proper parsers should supersede TXTH, once added */