mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-01-18 07:44:43 +01:00
commit
49bcedc5cb
@ -292,6 +292,10 @@
|
||||
RelativePath=".\meta\mzrt_streamfile.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\nus3bank_streamfile.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\ogg_vorbis_streamfile.h"
|
||||
>
|
||||
|
@ -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" />
|
||||
|
@ -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>
|
||||
|
@ -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[] = {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
126
src/meta/nus3bank_streamfile.h
Normal file
126
src/meta/nus3bank_streamfile.h
Normal 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_ */
|
@ -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};
|
||||
|
||||
|
@ -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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user