diff --git a/src/meta/adp_ongakukan.c b/src/meta/adp_ongakukan.c index 1284c836..552a9d22 100644 --- a/src/meta/adp_ongakukan.c +++ b/src/meta/adp_ongakukan.c @@ -9,8 +9,8 @@ VGMSTREAM* init_vgmstream_adp_ongakukan(STREAMFILE* sf) { bool sound_is_adpcm = false; int32_t fmt_size, fmt_offset; int32_t sample_rate, data_size; - int16_t channels; - + int16_t channels; + int32_t expected_size, pcm_size, diff, fact_offset; /* checks */ if (!is_id32be(0x00, sf, "RIFF")) @@ -24,21 +24,22 @@ VGMSTREAM* init_vgmstream_adp_ongakukan(STREAMFILE* sf) { data_size = get_streamfile_size(sf) - start_offset; /* RIFF size seem to match original PCM .wav, while encoded .adp data equals or is slightly smaller that that */ - uint32_t expected_size = (read_u32le(0x04, sf) - 0x24); - uint32_t pcm_size = data_size * 2 * sizeof(short); // * channels - if (pcm_size > expected_size) + expected_size = (read_u32le(0x04, sf) - 0x24); + pcm_size = data_size * 2 * sizeof(short); // * channels + diff = expected_size - pcm_size; + if (diff < 0 || diff > 2) return NULL; if (!is_id32be(0x08, sf, "WAVE")) return NULL; - if (!is_id32be(0x0c, sf, "fmt ")) - return NULL; + if (!is_id32be(0x0c, sf, "fmt ")) + return NULL; fmt_size = read_s32le(0x10, sf); /* depending on the adp, fmt_size alternates between 0x10 and 0x12 */ if (fmt_size < 0x10 || fmt_size > 0x12) goto fail; - fmt_offset = 0x14; + fmt_offset = 0x14; if (read_s16le(fmt_offset + 0x00, sf) != 0x0001) /* PCM format */ goto fail; @@ -49,11 +50,17 @@ VGMSTREAM* init_vgmstream_adp_ongakukan(STREAMFILE* sf) { if (read_s16le(fmt_offset + 0x0e, sf) != 16) /* PCM bit depth */ goto fail; /* rest of fmt header is the usual header for 16-bit PCM wav files: bitrate, block size, and the like (see riff.c) */ - /* if fmt_size == 0x12 there may be is an additional s16 field that's always zero, but not always. */ - - /* next chunk is at fixed offset, regardless of fmt_size (fmt_size 0x12 with "data" at 0x24 is possible). - * "data" has chunk size (does not match ADP size but original WAV) and "fact" chunk size 0x04 cut off) */ - if (!is_id32be(0x24, sf, "data") && !is_id32be(0x26, sf, "fact")) + /* if fmt_size == 0x12 there is an additional s16 field that may or may not be zero. */ + + /* depending on the adp, "fact" chunk is "movable" as we'll see later. */ + fact_offset = fmt_offset + fmt_size; + if (fact_offset < 0x24 || fact_offset > 0x28) + goto fail; + + /* for next chunk, if "data" then it's at fixed offset (0x24), regardless of fmt_size (fmt_size 0x12 with "data" at 0x24 is possible). + * if "fact" however, offset goes AFTER fmt_size (mostly 0x26 and rarely 0x24). + * "data" has chunk size (does not match ADP size but original WAV) and "fact" chunk size is always 0x04 (whether cut off or otherwise). */ + if (!is_id32be(0x24, sf, "data") && !is_id32be(fact_offset, sf, "fact")) goto fail; /* Ongagukan games using this format just read it by checking "ADP" extension in a provided file name,