Add .SNGW Ogg Vorbis (normal and encrypted) [Capcom PC games]

Also remove ifdefs for meta_OGG_x, there was no benefit
This commit is contained in:
bnnm 2018-01-10 22:34:14 +01:00
parent 7134610495
commit a67a83b9ed
4 changed files with 56 additions and 15 deletions

View File

@ -282,6 +282,7 @@ static const char* extension_list[] = {
"snd", "snd",
"snds", "snds",
"sng", "sng",
"sngw",
"snr", "snr",
"sns", "sns",
"snu", "snu",
@ -933,16 +934,15 @@ static const meta_info meta_info_list[] = {
{meta_NGC_VID1, "Neversoft VID1 header"}, {meta_NGC_VID1, "Neversoft VID1 header"},
{meta_PC_FLX, "Ultima IX .FLX header"}, {meta_PC_FLX, "Ultima IX .FLX header"},
{meta_MOGG, "Harmonix Music Systems MOGG Vorbis"}, {meta_MOGG, "Harmonix Music Systems MOGG Vorbis"},
#ifdef VGM_USE_VORBIS
{meta_OGG_VORBIS, "Ogg Vorbis"}, {meta_OGG_VORBIS, "Ogg Vorbis"},
{meta_OGG_SLI, "Ogg Vorbis with .sli (start,length) for looping"}, {meta_OGG_SLI, "Ogg Vorbis with .sli (start,length) for looping"},
{meta_OGG_SLI2, "Ogg Vorbis with .sli (from,to) for looping"}, {meta_OGG_SLI2, "Ogg Vorbis with .sli (from,to) for looping"},
{meta_OGG_SFL, "Ogg Vorbis with SFPL for looping"}, {meta_OGG_SFL, "Ogg Vorbis with SFPL for looping"},
{meta_OGG_UM3, "Ogg Vorbis, Ultramarine3 'encryption'"}, {meta_OGG_UM3, "Ogg Vorbis (Ultramarine3)"},
{meta_OGG_KOVS, "Ogg Vorbis, KOVS header"}, {meta_OGG_KOVS, "Ogg Vorbis (KOVS header)"},
{meta_OGG_PSYCH, "Ogg Vorbis, Psychic Software obfuscation"}, {meta_OGG_PSYCH, "Ogg Vorbis (Psychic Software)"},
#endif {meta_OGG_SNGW, "Ogg Vorbis (Capcom)"},
#ifdef VGM_USE_MP4V2 #ifdef VGM_USE_MP4V2
{meta_MP4, "AAC header"}, {meta_MP4, "AAC header"},
#endif #endif

View File

@ -103,6 +103,7 @@ typedef struct {
void (*decryption_callback)(void *ptr, size_t size, size_t nmemb, void *datasource); void (*decryption_callback)(void *ptr, size_t size, size_t nmemb, void *datasource);
uint8_t scd_xor; uint8_t scd_xor;
off_t scd_xor_length; off_t scd_xor_length;
uint32_t sngw_xor;
} vgm_vorbis_info_t; } vgm_vorbis_info_t;

View File

@ -110,6 +110,30 @@ static void psychic_ogg_decryption_callback(void *ptr, size_t size, size_t nmemb
} }
} }
static void sngw_ogg_decryption_callback(void *ptr, size_t size, size_t nmemb, void *datasource) {
size_t bytes_read = size*nmemb;
ogg_vorbis_streamfile * const ov_streamfile = datasource;
int i;
char *header_id = "OggS";
uint8_t key[4];
put_32bitBE(key, ov_streamfile->sngw_xor);
/* bytes are xor'd with key and nibble-swapped */
{
for (i = 0; i < bytes_read; i++) {
if (ov_streamfile->offset+i < 0x04) {
/* replace key in the first 4 bytes with "OggS" */
((uint8_t*)ptr)[i] = (uint8_t)header_id[(ov_streamfile->offset + i) % 4];
}
else {
uint8_t val = ((uint8_t*)ptr)[i] ^ key[(ov_streamfile->offset + i) % 4];
((uint8_t*)ptr)[i] = ((val << 4) & 0xf0) | ((val >> 4) & 0x0f);
}
}
}
}
/* Ogg Vorbis, by way of libvorbisfile; may contain loop comments */ /* Ogg Vorbis, by way of libvorbisfile; may contain loop comments */
VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) { VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) {
@ -121,6 +145,7 @@ VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) {
int is_um3 = 0; int is_um3 = 0;
int is_kovs = 0; int is_kovs = 0;
int is_psychic = 0; int is_psychic = 0;
int is_sngw = 0;
/* check extension */ /* check extension */
@ -130,6 +155,8 @@ VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) {
is_um3 = 1; is_um3 = 1;
} else if (check_extensions(streamFile,"kvs,kovs")) { /* .kvs: Atelier Sophie (PC), kovs: header id only? */ } else if (check_extensions(streamFile,"kvs,kovs")) { /* .kvs: Atelier Sophie (PC), kovs: header id only? */
is_kovs = 1; is_kovs = 1;
} else if (check_extensions(streamFile,"sngw")) { /* .sngw: Devil May Cry 4 SE (PC), Biohazard 6 (PC) */
is_sngw = 1;
} else { } else {
goto fail; goto fail;
} }
@ -167,12 +194,23 @@ VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) {
start_offset = 0x20; start_offset = 0x20;
} }
/* check SNGW (Capcom's MT Framework PC games), may be encrypted */
if (is_sngw) {
if (read_32bitBE(0x00,streamFile) != 0x4f676753) { /* "OggS" */
inf.sngw_xor = read_32bitBE(0x00,streamFile);
inf.decryption_callback = sngw_ogg_decryption_callback;
}
}
if (is_um3) { if (is_um3) {
inf.meta_type = meta_OGG_UM3; inf.meta_type = meta_OGG_UM3;
} else if (is_kovs) { } else if (is_kovs) {
inf.meta_type = meta_OGG_KOVS; inf.meta_type = meta_OGG_KOVS;
} else if (is_psychic) { } else if (is_psychic) {
inf.meta_type = meta_OGG_PSYCH; inf.meta_type = meta_OGG_PSYCH;
} else if (is_sngw) {
inf.meta_type = meta_OGG_SNGW;
} else { } else {
inf.meta_type = meta_OGG_VORBIS; inf.meta_type = meta_OGG_VORBIS;
} }
@ -220,6 +258,7 @@ VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, const ch
temp_streamfile.decryption_callback = vgm_inf->decryption_callback; temp_streamfile.decryption_callback = vgm_inf->decryption_callback;
temp_streamfile.scd_xor = vgm_inf->scd_xor; temp_streamfile.scd_xor = vgm_inf->scd_xor;
temp_streamfile.scd_xor_length = vgm_inf->scd_xor_length; temp_streamfile.scd_xor_length = vgm_inf->scd_xor_length;
temp_streamfile.sngw_xor = vgm_inf->sngw_xor;
/* open the ogg vorbis file for testing */ /* open the ogg vorbis file for testing */
memset(&temp_ovf, 0, sizeof(temp_ovf)); memset(&temp_ovf, 0, sizeof(temp_ovf));
@ -245,6 +284,7 @@ VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, const ch
data->ov_streamfile.decryption_callback = vgm_inf->decryption_callback; data->ov_streamfile.decryption_callback = vgm_inf->decryption_callback;
data->ov_streamfile.scd_xor = vgm_inf->scd_xor; data->ov_streamfile.scd_xor = vgm_inf->scd_xor;
data->ov_streamfile.scd_xor_length = vgm_inf->scd_xor_length; data->ov_streamfile.scd_xor_length = vgm_inf->scd_xor_length;
data->ov_streamfile.sngw_xor = vgm_inf->sngw_xor;
/* open the ogg vorbis file for real */ /* open the ogg vorbis file for real */
if (ov_open_callbacks(&data->ov_streamfile, &data->ogg_vorbis_file, NULL, 0, *callbacks_p)) if (ov_open_callbacks(&data->ov_streamfile, &data->ogg_vorbis_file, NULL, 0, *callbacks_p))

View File

@ -645,16 +645,15 @@ typedef enum {
meta_NGC_VID1, /* Neversoft .ogg (Gun GC) */ meta_NGC_VID1, /* Neversoft .ogg (Gun GC) */
meta_PC_FLX, /* Ultima IX PC */ meta_PC_FLX, /* Ultima IX PC */
meta_MOGG, /* Harmonix Music Systems MOGG Vorbis */ meta_MOGG, /* Harmonix Music Systems MOGG Vorbis */
#ifdef VGM_USE_VORBIS
meta_OGG_VORBIS, /* Ogg Vorbis */ meta_OGG_VORBIS, /* Ogg Vorbis */
meta_OGG_SLI, /* Ogg Vorbis file w/ companion .sli for looping */ meta_OGG_SLI, /* Ogg Vorbis file w/ companion .sli for looping */
meta_OGG_SLI2, /* Ogg Vorbis file w/ different styled .sli for looping */ meta_OGG_SLI2, /* Ogg Vorbis file w/ different styled .sli for looping */
meta_OGG_SFL, /* Ogg Vorbis file w/ .sfl (RIFF SFPL) for looping */ meta_OGG_SFL, /* Ogg Vorbis file w/ .sfl (RIFF SFPL) for looping */
meta_OGG_UM3, /* Ogg Vorbis with first 0x800 bytes XOR 0xFF */ meta_OGG_UM3, /* Ogg Vorbis with optional first 0x800 bytes XOR 0xFF */
meta_OGG_KOVS, /* Ogg Vorbis with exta header and 0x100 bytes XOR */ meta_OGG_KOVS, /* Ogg Vorbis with extra header and 0x100 bytes XOR */
meta_OGG_PSYCH, /* Ogg Vorbis with all bytes -0x23*/ meta_OGG_PSYCH, /* Ogg Vorbis with all bytes -0x23 */
#endif meta_OGG_SNGW, /* Ogg Vorbis with optional key XOR + nibble swap */
#ifdef VGM_USE_MP4V2 #ifdef VGM_USE_MP4V2
meta_MP4, /* AAC (iOS) */ meta_MP4, /* AAC (iOS) */
#endif #endif
@ -798,11 +797,12 @@ typedef struct {
ogg_int64_t size; ogg_int64_t size;
ogg_int64_t other_header_bytes; ogg_int64_t other_header_bytes;
/* XOR setup (SCD) */ /* decryption setup */
int decryption_enabled; void (*decryption_callback)(void *ptr, size_t size, size_t nmemb, void *datasource);
void (*decryption_callback)(void *ptr, size_t size, size_t nmemb, void *datasource, int bytes_read);
uint8_t scd_xor; uint8_t scd_xor;
off_t scd_xor_length; off_t scd_xor_length;
uint32_t sngw_xor;
} ogg_vorbis_streamfile; } ogg_vorbis_streamfile;
typedef struct { typedef struct {