Merge pull request #519 from bnnm/imas

imas
This commit is contained in:
bnnm 2019-11-26 20:41:15 +01:00 committed by GitHub
commit 49bcedc5cb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 188 additions and 3 deletions

View File

@ -292,6 +292,10 @@
RelativePath=".\meta\mzrt_streamfile.h"
>
</File>
<File
RelativePath=".\meta\nus3bank_streamfile.h"
>
</File>
<File
RelativePath=".\meta\ogg_vorbis_streamfile.h"
>

View File

@ -118,6 +118,7 @@
<ClInclude Include="meta\xavs_streamfile.h" />
<ClInclude Include="meta\mta2_streamfile.h" />
<ClInclude Include="meta\mzrt_streamfile.h" />
<ClInclude Include="meta\nus3bank_streamfile.h" />
<ClInclude Include="meta\ogg_vorbis_streamfile.h" />
<ClInclude Include="meta\opus_interleave_streamfile.h" />
<ClInclude Include="meta\riff_ogg_streamfile.h" />

View File

@ -116,6 +116,9 @@
<ClInclude Include="meta\mzrt_streamfile.h">
<Filter>meta\Header Files</Filter>
</ClInclude>
<ClInclude Include="meta\nus3bank_streamfile.h">
<Filter>meta\Header Files</Filter>
</ClInclude>
<ClInclude Include="meta\ogg_vorbis_streamfile.h">
<Filter>meta\Header Files</Filter>
</ClInclude>

View File

@ -184,6 +184,9 @@ static const adxkey_info adxkey8_list[] = {
/* Gintama Gin-san to Issho! Boku no Kabukichou Nikki (PS2) [Bandai Namco?] */
{0x67CD,0x5CA7,0x655F, "gt25809",0},
/* Lucky Star: RAvish Romance (PS2) [Vridge] */
{0x5347,0x4FB7,0x6415, "LUCKYSRARPS2",0},
};
static const adxkey_info adxkey9_list[] = {

View File

@ -746,6 +746,7 @@ VGMSTREAM * init_vgmstream_hd3_bd3(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_nus3bank(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_nus3bank_encrypted(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_scd_sscf(STREAMFILE *streamFile);

View File

@ -1,7 +1,9 @@
#include "meta.h"
#include "../coding/coding.h"
typedef enum { IDSP, IVAG, BNSF, RIFF, OPUS, } nus3bank_codec;
#include "nus3bank_streamfile.h"
typedef enum { IDSP, IVAG, BNSF, RIFF, OPUS, RIFF_ENC, } nus3bank_codec;
/* .nus3bank - Namco's newest audio container [Super Smash Bros (Wii U), idolmaster (PS4))] */
VGMSTREAM * init_vgmstream_nus3bank(STREAMFILE *streamFile) {
@ -145,7 +147,7 @@ VGMSTREAM * init_vgmstream_nus3bank(STREAMFILE *streamFile) {
goto fail;
}
//todo improve, codec may be in one of the tone sub-chunks (or other chunk? one bank seems to share codec)
//todo improve, codec may be in one of the tone sub-chunks (or other chunk? one bank seems to use one codec)
codec_id = read_32bitBE(subfile_offset, streamFile);
switch(codec_id) {
case 0x49445350: /* "IDSP" [Super Smash Bros. for 3DS (3DS)] */
@ -173,7 +175,11 @@ VGMSTREAM * init_vgmstream_nus3bank(STREAMFILE *streamFile) {
fake_ext = "ivag";
break;
case 0x552AAF17: /* "RIFF" with encrypted header (not data) [THE iDOLM@STER 2 (X360)] */ //TODO
case 0x552AAF17: /* "RIFF" with encrypted header (not data) [THE iDOLM@STER 2 (X360)] */
codec = RIFF_ENC;
fake_ext = "xma";
break;
default:
VGM_LOG("NUS3BANK: unknown codec %x\n", codec_id);
goto fail;
@ -212,6 +218,11 @@ VGMSTREAM * init_vgmstream_nus3bank(STREAMFILE *streamFile) {
if (!vgmstream) goto fail;
break;
case RIFF_ENC:
vgmstream = init_vgmstream_nus3bank_encrypted(temp_sf);
if (!vgmstream) goto fail;
break;
default:
goto fail;
}
@ -229,3 +240,30 @@ fail:
close_vgmstream(vgmstream);
return NULL;
}
/* encrypted RIFF from the above, in case kids try to extract and play single files */
VGMSTREAM* init_vgmstream_nus3bank_encrypted(STREAMFILE *sf) {
VGMSTREAM *vgmstream = NULL;
STREAMFILE *temp_sf = NULL;
/* checks */
if (!check_extensions(sf, "nus3bank,xma"))
goto fail;
if (read_u32be(0x00, sf) != 0x552AAF17) /* "RIFF" encrypted */
goto fail;
temp_sf = setup_nus3bank_streamfile(sf, 0x00);
if (!temp_sf) goto fail;
vgmstream = init_vgmstream_xma(temp_sf);
if (!vgmstream) goto fail;
close_streamfile(temp_sf);
return vgmstream;
fail:
close_streamfile(temp_sf);
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -0,0 +1,126 @@
#ifndef _NUS3BANK_STREAMFILE_H_
#define _NUS3BANK_STREAMFILE_H_
#include "../streamfile.h"
static uint32_t swap_endian32(uint32_t v) {
return ((v & 0xff000000) >> 24u) |
((v & 0x00ff0000) >> 8u) |
((v & 0x0000ff00) << 8u) |
((v & 0x000000ff) << 24u);
}
#define KEY_MAX_SIZE 0x1000
typedef struct {
uint8_t key[KEY_MAX_SIZE];
int key_len;
} io_data_t;
static size_t io_read(STREAMFILE *sf, uint8_t *dest, off_t offset, size_t length, io_data_t *data) {
int i;
size_t bytes = read_streamfile(dest, offset, length, sf);
/* decrypt data (xor) */
if (offset < data->key_len) {
for (i = 0; i < bytes; i++) {
if (offset + i < data->key_len)
dest[i] ^= data->key[offset + i];
}
}
return bytes;
}
/* decrypts RIFF streams in NUS3BANK */
static STREAMFILE* setup_nus3bank_streamfile(STREAMFILE *sf, off_t start) {
STREAMFILE *new_sf = NULL;
io_data_t io_data = {0};
/* setup key */
{
uint32_t base_key, chunk_key;
uint8_t buf[KEY_MAX_SIZE];
uint32_t chunk_type, chunk_size;
int pos, data_pos, bytes;
/* Header is XORed with a base key and a derived chunk type/size key, while chunk data is XORed with
* unencrypted data itself, so we need to find where "data" starts then do another pass to properly set key.
* Original code handles RIFF's "data" and also BNSF's "sdat" too, encrypted BNSF aren't known though. */
bytes = read_streamfile(buf, start, sizeof(buf), sf);
if (bytes < 0x800) goto fail; /* files of 1 XMA block do exist, but not less */
base_key = 0x0763E951;
chunk_type = get_u32be(buf + 0x00) ^ base_key;
chunk_size = get_u32be(buf + 0x04) ^ base_key;
if (chunk_type != 0x52494646) /* "RIFF" */
goto fail;
chunk_key = base_key ^ (((chunk_size >> 16u) & 0x0000FFFF) | ((chunk_size << 16u) & 0xFFFF0000)); /* ROTr 16 size */
/* find "data" */
pos = 0x0c;
while(pos < sizeof(buf)) {
chunk_type = get_u32be(buf + pos + 0x00) ^ chunk_key;
chunk_size = get_u32be(buf + pos + 0x04) ^ chunk_key;
chunk_size = swap_endian32(chunk_size);
pos += 0x08;
if (chunk_type == 0x64617461) { /* "data" */
data_pos = pos;
break;
}
if (pos + chunk_size > sizeof(buf) - 0x08) {
VGM_LOG("NUS3 SF: header too big\n");
goto fail; /* max around 0x400 */
}
pos += chunk_size;
}
/* setup key */
put_u32be(io_data.key + 0x00, base_key);
put_u32be(io_data.key + 0x04, base_key);
put_u32be(io_data.key + 0x08, chunk_key);
pos = 0x0c; /* after WAVE */
while (pos < data_pos) {
chunk_type = get_u32be(buf + pos + 0x00) ^ chunk_key;
chunk_size = get_u32be(buf + pos + 0x04) ^ chunk_key;
chunk_size = swap_endian32(chunk_size);
put_u32be(io_data.key + pos + 0x00, chunk_key);
put_u32be(io_data.key + pos + 0x04, chunk_key);
pos += 0x08;
if (pos >= data_pos)
break;
/* buf must contain data of at least chunk_size */
if (data_pos + chunk_size >= sizeof(buf)) {
VGM_LOG("NUS3 SF: chunk too big\n");
goto fail;
}
memcpy(io_data.key + pos, buf + data_pos, chunk_size);
pos += chunk_size;
}
io_data.key_len = data_pos;
}
new_sf = open_wrap_streamfile(sf);
new_sf = open_io_streamfile(new_sf, &io_data, sizeof(io_data_t), io_read, NULL);
return new_sf;
fail:
close_streamfile(sf);
return NULL;
}
#endif /* _NUS3BANK_STREAMFILE_H_ */

View File

@ -59,6 +59,14 @@ void put_16bitBE(uint8_t * buf, int16_t i);
void put_32bitBE(uint8_t * buf, int32_t i);
/* alias of the above */ //TODO: improve
#define put_u8 put_8bit
#define put_u16le put_16bitLE
#define put_u32le put_32bitLE
#define put_u16be put_16bitBE
#define put_u32be put_32bitBE
/* signed nibbles come up a lot */
static int nibble_to_int[16] = {0,1,2,3,4,5,6,7,-8,-7,-6,-5,-4,-3,-2,-1};

View File

@ -405,6 +405,7 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
init_vgmstream_hd3_bd3,
init_vgmstream_bnk_sony,
init_vgmstream_nus3bank,
init_vgmstream_nus3bank_encrypted,
init_vgmstream_scd_sscf,
init_vgmstream_dsp_sps_n1,
init_vgmstream_dsp_itl_ch,