From a67a83b9ed4a6277d7b35a8e54eca80aed2910f1 Mon Sep 17 00:00:00 2001 From: bnnm Date: Wed, 10 Jan 2018 22:34:14 +0100 Subject: [PATCH] Add .SNGW Ogg Vorbis (normal and encrypted) [Capcom PC games] Also remove ifdefs for meta_OGG_x, there was no benefit --- src/formats.c | 12 ++++++------ src/meta/meta.h | 1 + src/meta/ogg_vorbis_file.c | 40 ++++++++++++++++++++++++++++++++++++++ src/vgmstream.h | 18 ++++++++--------- 4 files changed, 56 insertions(+), 15 deletions(-) diff --git a/src/formats.c b/src/formats.c index 975a3c54..a23b82ab 100644 --- a/src/formats.c +++ b/src/formats.c @@ -282,6 +282,7 @@ static const char* extension_list[] = { "snd", "snds", "sng", + "sngw", "snr", "sns", "snu", @@ -933,16 +934,15 @@ static const meta_info meta_info_list[] = { {meta_NGC_VID1, "Neversoft VID1 header"}, {meta_PC_FLX, "Ultima IX .FLX header"}, {meta_MOGG, "Harmonix Music Systems MOGG Vorbis"}, - -#ifdef VGM_USE_VORBIS {meta_OGG_VORBIS, "Ogg Vorbis"}, {meta_OGG_SLI, "Ogg Vorbis with .sli (start,length) for looping"}, {meta_OGG_SLI2, "Ogg Vorbis with .sli (from,to) for looping"}, {meta_OGG_SFL, "Ogg Vorbis with SFPL for looping"}, - {meta_OGG_UM3, "Ogg Vorbis, Ultramarine3 'encryption'"}, - {meta_OGG_KOVS, "Ogg Vorbis, KOVS header"}, - {meta_OGG_PSYCH, "Ogg Vorbis, Psychic Software obfuscation"}, - #endif + {meta_OGG_UM3, "Ogg Vorbis (Ultramarine3)"}, + {meta_OGG_KOVS, "Ogg Vorbis (KOVS header)"}, + {meta_OGG_PSYCH, "Ogg Vorbis (Psychic Software)"}, + {meta_OGG_SNGW, "Ogg Vorbis (Capcom)"}, + #ifdef VGM_USE_MP4V2 {meta_MP4, "AAC header"}, #endif diff --git a/src/meta/meta.h b/src/meta/meta.h index 55c4d26a..5f35eb26 100644 --- a/src/meta/meta.h +++ b/src/meta/meta.h @@ -103,6 +103,7 @@ typedef struct { void (*decryption_callback)(void *ptr, size_t size, size_t nmemb, void *datasource); uint8_t scd_xor; off_t scd_xor_length; + uint32_t sngw_xor; } vgm_vorbis_info_t; diff --git a/src/meta/ogg_vorbis_file.c b/src/meta/ogg_vorbis_file.c index 64b2a122..8372dd0d 100644 --- a/src/meta/ogg_vorbis_file.c +++ b/src/meta/ogg_vorbis_file.c @@ -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 */ VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) { @@ -121,6 +145,7 @@ VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) { int is_um3 = 0; int is_kovs = 0; int is_psychic = 0; + int is_sngw = 0; /* check extension */ @@ -130,6 +155,8 @@ VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) { is_um3 = 1; } else if (check_extensions(streamFile,"kvs,kovs")) { /* .kvs: Atelier Sophie (PC), kovs: header id only? */ is_kovs = 1; + } else if (check_extensions(streamFile,"sngw")) { /* .sngw: Devil May Cry 4 SE (PC), Biohazard 6 (PC) */ + is_sngw = 1; } else { goto fail; } @@ -167,12 +194,23 @@ VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) { 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) { inf.meta_type = meta_OGG_UM3; } else if (is_kovs) { inf.meta_type = meta_OGG_KOVS; } else if (is_psychic) { inf.meta_type = meta_OGG_PSYCH; + } else if (is_sngw) { + inf.meta_type = meta_OGG_SNGW; } else { 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.scd_xor = vgm_inf->scd_xor; 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 */ 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.scd_xor = vgm_inf->scd_xor; 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 */ if (ov_open_callbacks(&data->ov_streamfile, &data->ogg_vorbis_file, NULL, 0, *callbacks_p)) diff --git a/src/vgmstream.h b/src/vgmstream.h index 6437e999..8360eb23 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -645,16 +645,15 @@ typedef enum { meta_NGC_VID1, /* Neversoft .ogg (Gun GC) */ meta_PC_FLX, /* Ultima IX PC */ meta_MOGG, /* Harmonix Music Systems MOGG Vorbis */ - -#ifdef VGM_USE_VORBIS meta_OGG_VORBIS, /* Ogg Vorbis */ 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_SFL, /* Ogg Vorbis file w/ .sfl (RIFF SFPL) for looping */ - meta_OGG_UM3, /* Ogg Vorbis with first 0x800 bytes XOR 0xFF */ - meta_OGG_KOVS, /* Ogg Vorbis with exta header and 0x100 bytes XOR */ - meta_OGG_PSYCH, /* Ogg Vorbis with all bytes -0x23*/ -#endif + meta_OGG_UM3, /* Ogg Vorbis with optional first 0x800 bytes XOR 0xFF */ + meta_OGG_KOVS, /* Ogg Vorbis with extra header and 0x100 bytes XOR */ + meta_OGG_PSYCH, /* Ogg Vorbis with all bytes -0x23 */ + meta_OGG_SNGW, /* Ogg Vorbis with optional key XOR + nibble swap */ + #ifdef VGM_USE_MP4V2 meta_MP4, /* AAC (iOS) */ #endif @@ -798,11 +797,12 @@ typedef struct { ogg_int64_t size; ogg_int64_t other_header_bytes; - /* XOR setup (SCD) */ - int decryption_enabled; - void (*decryption_callback)(void *ptr, size_t size, size_t nmemb, void *datasource, int bytes_read); + /* decryption setup */ + void (*decryption_callback)(void *ptr, size_t size, size_t nmemb, void *datasource); uint8_t scd_xor; off_t scd_xor_length; + uint32_t sngw_xor; + } ogg_vorbis_streamfile; typedef struct {