mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-01-31 12:23:44 +01:00
Merge pull request #1279 from bnnm/ahx-misc
- Reject wrong RWSD - Add AHX key auto-detection and fix decryption - Add .bcv extension [The Bigs (PSP)] - Add RIFF .mus extension [Burnout Legends/Dominator (PSP)] - cleanup
This commit is contained in:
commit
e7873968b4
2
Makefile
2
Makefile
@ -58,7 +58,7 @@ export RMF SHELL CC AR STRIP WINDRES DLLTOOL
|
||||
###############################################################################
|
||||
### build defs
|
||||
|
||||
DEF_CFLAGS += -ffast-math -O3 -Wall -Werror=format-security -Wdeclaration-after-statement -Wvla -Wimplicit-function-declaration -Wignored-qualifiers
|
||||
DEF_CFLAGS += -ffast-math -O3 -Wall -Werror=format-security -Wvla -Wimplicit-function-declaration -Wignored-qualifiers
|
||||
|
||||
VGM_DEBUG_FLAGS = 0
|
||||
ifeq ($(VGM_DEBUG_FLAGS),1)
|
||||
|
@ -473,6 +473,13 @@ typedef enum {
|
||||
MPEG_EAMP3 /* custom frame header + MPEG frame + PCM blocks */
|
||||
} mpeg_custom_t;
|
||||
|
||||
typedef struct {
|
||||
int type;
|
||||
uint16_t key1;
|
||||
uint16_t key2;
|
||||
uint16_t key3;
|
||||
} crikey_t;
|
||||
|
||||
/* config for the above modes */
|
||||
typedef struct {
|
||||
int channels; /* max channels */
|
||||
@ -485,11 +492,7 @@ typedef struct {
|
||||
int encryption; /* encryption mode */
|
||||
int big_endian;
|
||||
int skip_samples;
|
||||
/* for AHX */
|
||||
int cri_type;
|
||||
uint16_t cri_key1;
|
||||
uint16_t cri_key2;
|
||||
uint16_t cri_key3;
|
||||
crikey_t crikey; /* for AHX */
|
||||
} mpeg_custom_config;
|
||||
|
||||
mpeg_codec_data* init_mpeg(STREAMFILE* sf, off_t start_offset, coding_t *coding_type, int channels);
|
||||
@ -504,6 +507,7 @@ long mpeg_bytes_to_samples(long bytes, const mpeg_codec_data* data);
|
||||
|
||||
uint32_t mpeg_get_tag_size(STREAMFILE* sf, uint32_t offset, uint32_t header);
|
||||
int mpeg_get_frame_info(STREAMFILE* sf, off_t offset, mpeg_frame_info* info);
|
||||
int test_ahx_key(STREAMFILE* sf, off_t offset, crikey_t* crikey);
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -1,111 +1,223 @@
|
||||
#include "mpeg_decoder.h"
|
||||
|
||||
#ifdef VGM_USE_MPEG
|
||||
#include "mpeg_decoder.h"
|
||||
#include "../util/bitstream_msb.h"
|
||||
#include "coding.h"
|
||||
|
||||
#define MPEG_AHX_EXPECTED_FRAME_SIZE 0x414
|
||||
|
||||
static int ahx_decrypt_type08(uint8_t * buffer, mpeg_custom_config *config);
|
||||
/* AHX is more or less VBR MP2 using a fixed header (0xFFF5E0C0) that sets frame size 0x414 (1ch, 160kbps, 22050Hz)
|
||||
* but are typically much shorter (ignores padding), output sample rate is also ignored.
|
||||
*
|
||||
* MPEG1 Layer II (MP2) bitstream format for reference:
|
||||
* - MPEG header, 32b
|
||||
* - 'bit allocation' indexes (MP2's config determines bands and table with bit size per band, in AHX's case 30 bands and total 107 bits)
|
||||
* - 16-bit CRC if set in header (never in AHX)
|
||||
* - scale factor selection info (SCFSI), 2b per band/channel (if band has bit alloc set)
|
||||
* - scale factors, bits depending on selection info (if band has bit alloc set)
|
||||
* - quantized samples, bits depending on bit alloc info
|
||||
* - padding (removed in AHX)
|
||||
*/
|
||||
|
||||
/* writes data to the buffer and moves offsets, transforming AHX frames as needed */
|
||||
int mpeg_custom_parse_frame_ahx(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data, int num_stream) {
|
||||
mpeg_custom_stream *ms = data->streams[num_stream];
|
||||
size_t current_data_size = 0;
|
||||
size_t file_size = get_streamfile_size(stream->streamfile);
|
||||
|
||||
/* AHX has a 0xFFF5E0C0 header with frame size 0x414 (160kbps, 22050Hz) but they actually are much shorter */
|
||||
#define AHX_BANDS 30
|
||||
#define AHX_GRANULES 12
|
||||
static const uint8_t AHX_BITALLOC_TABLE[32] = { 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 };
|
||||
static const uint8_t AHX_OFFSET_TABLE[5][16] = {
|
||||
{ 0 },
|
||||
{ 0 },
|
||||
{ 0, 1, 3, 4, },
|
||||
{ 0, 1, 3, 4, 5, 6, 7, 8, },
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 }
|
||||
};
|
||||
static const int8_t AHX_QBITS_TABLE[17] = { -5, -7, 3, -10, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
|
||||
|
||||
/* read supposed frame size first (to minimize reads) */
|
||||
ms->bytes_in_buffer = read_streamfile(ms->buffer, stream->offset, MPEG_AHX_EXPECTED_FRAME_SIZE, stream->streamfile);
|
||||
/* Decrypts and tests a AHX frame with current by reading all bits, as wrong keys should go over size. Reverse engineered
|
||||
* from CRI libs. (MPEG1 Layer II code abridged for AHX, which is always mono and has fixed bands/tables, some info from ahx2wav.c) */
|
||||
static int ahx_decrypt(uint8_t* buf, int curr_size, crikey_t* crikey) {
|
||||
uint32_t bit_alloc[AHX_BANDS] = {0};
|
||||
uint32_t scfsi[AHX_BANDS] = {0};
|
||||
bitstream_t ib = {0};
|
||||
bitstream_t ob = {0};
|
||||
|
||||
/* find actual frame size by looking for the next frame header */
|
||||
{
|
||||
uint32_t current_header = get_u32be(ms->buffer);
|
||||
int next_pos = 0x04;
|
||||
bm_setup(&ib, buf, curr_size); /* frame */
|
||||
bm_setup(&ob, buf, curr_size); /* decrypted frame */
|
||||
|
||||
while (next_pos <= MPEG_AHX_EXPECTED_FRAME_SIZE) {
|
||||
uint32_t next_header = get_u32be(ms->buffer + next_pos);
|
||||
/* MPEG header (fixed in AHX, otherwise layer/bitrate/channels sets bands+tables) */
|
||||
bm_skip(&ib, 32);
|
||||
bm_skip(&ob, 32);
|
||||
|
||||
if (current_header == next_header) {
|
||||
current_data_size = next_pos;
|
||||
break;
|
||||
}
|
||||
/* read bit allocs for later */
|
||||
for (int i = 0; i < AHX_BANDS; i++) {
|
||||
int ba_bits = AHX_BITALLOC_TABLE[i];
|
||||
|
||||
/* AHXs end in a 0x0c footer (0x41485845 28632943 52490000 / "AHXE(c)CRI\0\0") */
|
||||
if (stream->offset + next_pos + 0x0c >= file_size) {
|
||||
current_data_size = next_pos;
|
||||
break;
|
||||
}
|
||||
bm_get (&ib, ba_bits, &bit_alloc[i]);
|
||||
bm_skip(&ob, ba_bits);
|
||||
}
|
||||
|
||||
next_pos++;
|
||||
/* get first scalefactor info to decide key */
|
||||
if (bit_alloc[0]) {
|
||||
bm_get (&ib, 2, &scfsi[0]);
|
||||
bm_skip(&ob, 2);
|
||||
}
|
||||
|
||||
uint16_t key;
|
||||
switch(scfsi[0]) {
|
||||
case 1: key = crikey->key1; break;
|
||||
case 2: key = crikey->key2; break;
|
||||
case 3: key = crikey->key3; break;
|
||||
default: key = 0; /* 0: no key (common in null frames) */
|
||||
}
|
||||
|
||||
/* decrypt rest of scalefactors (only first ones are encrypted though) */
|
||||
for (int i = 1; i < AHX_BANDS; i++) {
|
||||
if (bit_alloc[i]) {
|
||||
bm_get (&ib, 2, &scfsi[i]);
|
||||
scfsi[i] ^= (key & 3);
|
||||
bm_put(&ob, 2, scfsi[i]);
|
||||
}
|
||||
key >>= 2;
|
||||
}
|
||||
|
||||
/* read scalefactors (past this point no need to decrypt/write frame) */
|
||||
for (int i = 0; i < AHX_BANDS; i++) {
|
||||
if (bit_alloc[i] == 0)
|
||||
continue;
|
||||
|
||||
switch(scfsi[i]) {
|
||||
case 0: bm_skip(&ib, 6 * 3); break;
|
||||
case 1:
|
||||
case 3: bm_skip(&ib, 6 * 2); break;
|
||||
case 2: bm_skip(&ib, 6 * 1); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
if (current_data_size == 0 || current_data_size > ms->buffer_size || current_data_size > MPEG_AHX_EXPECTED_FRAME_SIZE) {
|
||||
VGM_LOG("MPEG AHX: incorrect data_size 0x%x\n", current_data_size);
|
||||
/* read quants */
|
||||
for (int gr = 0; gr < AHX_GRANULES; gr++) {
|
||||
for (int i = 0; i < AHX_BANDS; i++) {
|
||||
int ba_value = bit_alloc[i];
|
||||
if (ba_value == 0)
|
||||
continue;
|
||||
|
||||
int ba_bits = AHX_BITALLOC_TABLE[i];
|
||||
int qb_index = AHX_OFFSET_TABLE[ba_bits][ba_value - 1];
|
||||
int qbits = AHX_QBITS_TABLE[qb_index];
|
||||
|
||||
if (qbits < 0)
|
||||
qbits = -qbits;
|
||||
else
|
||||
qbits = qbits * 3; /* 3 qs */
|
||||
|
||||
int ok = bm_skip(&ib, qbits);
|
||||
if (!ok) goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* read padding */
|
||||
{
|
||||
int bpos = bm_pos(&ib);
|
||||
if (bpos % 8) {
|
||||
bm_skip(&ib, 8 - (bpos % 8));
|
||||
}
|
||||
}
|
||||
|
||||
/* if file was properly read/decrypted this size should land in next frame header or near EOF */
|
||||
return bm_pos(&ib) / 8;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* writes data to the buffer and moves offsets, transforming AHX frames as needed */
|
||||
int mpeg_custom_parse_frame_ahx(VGMSTREAMCHANNEL* stream, mpeg_codec_data* data, int num_stream) {
|
||||
mpeg_custom_stream *ms = data->streams[num_stream];
|
||||
size_t curr_size = 0;
|
||||
size_t file_size = get_streamfile_size(stream->streamfile);
|
||||
|
||||
|
||||
/* Find actual frame size by looking for the next frame header. Not very elegant but simpler, works with encrypted AHX,
|
||||
* and possibly faster than reading frame size's bits with ahx_decrypt */
|
||||
{
|
||||
ms->bytes_in_buffer = read_streamfile(ms->buffer, stream->offset, MPEG_AHX_EXPECTED_FRAME_SIZE + 0x04, stream->streamfile);
|
||||
|
||||
uint32_t curr_header = get_u32be(ms->buffer);
|
||||
int pos = 0x04;
|
||||
while (pos <= MPEG_AHX_EXPECTED_FRAME_SIZE) {
|
||||
|
||||
/* next sync test */
|
||||
if (ms->buffer[pos] == 0xFF) {
|
||||
uint32_t next_header = get_u32be(ms->buffer + pos);
|
||||
if (curr_header == next_header) {
|
||||
curr_size = pos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* AHX footer (0x8001000C 41485845 28632943 52490000 = 0x8001 tag + size + "AHXE(c)CRI\0\0") */
|
||||
if (stream->offset + pos + 0x10 >= file_size) {
|
||||
curr_size = pos;
|
||||
break;
|
||||
}
|
||||
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
|
||||
if (curr_size == 0 || curr_size > ms->buffer_size || curr_size > MPEG_AHX_EXPECTED_FRAME_SIZE) {
|
||||
VGM_LOG("MPEG AHX: incorrect data_size 0x%x\n", curr_size);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* 0-fill up to expected size to keep mpg123 happy */
|
||||
memset(ms->buffer + current_data_size, 0, MPEG_AHX_EXPECTED_FRAME_SIZE - current_data_size);
|
||||
memset(ms->buffer + curr_size, 0, MPEG_AHX_EXPECTED_FRAME_SIZE - curr_size);
|
||||
ms->bytes_in_buffer = MPEG_AHX_EXPECTED_FRAME_SIZE;
|
||||
|
||||
|
||||
/* decrypt if needed */
|
||||
switch(data->config.encryption) {
|
||||
case 0x00: break;
|
||||
case 0x08: ahx_decrypt_type08(ms->buffer, &data->config); break;
|
||||
default:
|
||||
VGM_LOG("MPEG AHX: unknown encryption 0x%x\n", data->config.encryption);
|
||||
break; /* garbled frame */
|
||||
/* decrypt if needed (only 0x08 is known but 0x09 is probably the same) */
|
||||
if (data->config.encryption == 0x08) {
|
||||
ahx_decrypt(ms->buffer, curr_size, &data->config.crikey);
|
||||
}
|
||||
|
||||
/* update offsets */
|
||||
stream->offset += current_data_size;
|
||||
if (stream->offset + 0x0c >= file_size)
|
||||
stream->offset = file_size; /* skip 0x0c footer to reach EOF (shouldn't happen normally) */
|
||||
stream->offset += curr_size;
|
||||
if (stream->offset + 0x10 >= file_size)
|
||||
stream->offset = file_size; /* skip footer to reach EOF (shouldn't happen normally) */
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Decrypts an AHX type 0x08 (keystring) encrypted frame. Algorithm by Thealexbarney */
|
||||
static int ahx_decrypt_type08(uint8_t * buffer, mpeg_custom_config *config) {
|
||||
int i, index, encrypted_bits;
|
||||
uint32_t value;
|
||||
uint16_t current_key;
|
||||
|
||||
/* encryption 0x08 modifies a few bits every frame, here we decrypt and write to data buffer */
|
||||
#define AHX_KEY_BUFFER 0x2000
|
||||
#define AHX_KEY_TEST_FRAMES 15 /* wrong keys may work ok in some frames */
|
||||
|
||||
/* derive keystring to 3 primes, using the type 0x08 method, and assign each an index of 1/2/3 (0=no key) */
|
||||
/* (externally done for now, see: https://github.com/Thealexbarney/VGAudio/blob/2.0/src/VGAudio/Codecs/CriAdx/CriAdxKey.cs) */
|
||||
/* check if current key ends properly in frame syncs */
|
||||
int test_ahx_key(STREAMFILE* sf, off_t offset, crikey_t* crikey) {
|
||||
int bytes;
|
||||
uint8_t buf[AHX_KEY_BUFFER];
|
||||
const int buf_size = sizeof(buf);
|
||||
int pos = 0;
|
||||
uint32_t base_sync, curr_sync;
|
||||
|
||||
/* read 2b from a bitstream offset to decrypt, and use it as an index to get the key.
|
||||
* AHX encrypted bitstream starts at 107b (0x0d*8+3), every frame, and seem to always use index 2 */
|
||||
value = get_u32be(buffer + 0x0d);
|
||||
index = (value >> (32-3-2)) & 0x03;
|
||||
switch(index) {
|
||||
case 0: current_key = 0; break;
|
||||
case 1: current_key = config->cri_key1; break;
|
||||
case 2: current_key = config->cri_key2; break;
|
||||
case 3: current_key = config->cri_key3; break;
|
||||
default: goto fail;
|
||||
bytes = read_streamfile(buf, offset, buf_size, sf);
|
||||
//if (bytes != buf_size) goto fail; /* possible in small AHX */
|
||||
|
||||
base_sync = get_u32be(buf + 0x00);
|
||||
for (int i = 0; i < AHX_KEY_TEST_FRAMES; i++) {
|
||||
|
||||
int size = ahx_decrypt(buf + pos, bytes, crikey);
|
||||
if (size <= 0 || size >= bytes - 0x04) goto fail;
|
||||
|
||||
bytes -= size;
|
||||
pos += size;
|
||||
|
||||
curr_sync = get_u32be(buf + pos);
|
||||
if (curr_sync == 0x00800100) /* EOF tag */
|
||||
break;
|
||||
if (base_sync != curr_sync)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* AHX for DC: 16b, normal: 6b (no idea, probably some Layer II field) */
|
||||
encrypted_bits = config->cri_type == 0x10 ? 16 : 6;
|
||||
|
||||
/* decrypt next bitstream 2b pairs, up to 16b (max key size):
|
||||
* - read 2b from bitstream (from higher to lower)
|
||||
* - read 2b from key (from lower to higher)
|
||||
* - XOR them to decrypt */
|
||||
for (i = 0; i < encrypted_bits; i+=2) {
|
||||
uint32_t xor_2b = (current_key >> i) & 0x03;
|
||||
value ^= ((xor_2b << (32-3-2-2)) >> i);
|
||||
}
|
||||
|
||||
/* write output */
|
||||
put_32bitBE(buffer + 0x0d, value);
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
return 0;
|
||||
|
@ -1,5 +1,5 @@
|
||||
#include "mpeg_decoder.h"
|
||||
#include "mpeg_bitreader.h"
|
||||
#include "../util/bitstream_msb.h"
|
||||
|
||||
#ifdef VGM_USE_MPEG
|
||||
|
||||
@ -108,7 +108,7 @@ int mpeg_custom_setup_init_ealayer3(STREAMFILE* sf, off_t start_offset, mpeg_cod
|
||||
{
|
||||
ib.sf = sf;
|
||||
ib.offset = start_offset;
|
||||
ib.is.buf = ib.buf;
|
||||
bm_setup(&ib.is, ib.buf, 0); // filled later
|
||||
|
||||
ok = ealayer3_parse_frame(data, -1, &ib, &eaf);
|
||||
if (!ok) goto fail;
|
||||
@ -156,7 +156,7 @@ int mpeg_custom_parse_frame_ealayer3(VGMSTREAMCHANNEL* stream, mpeg_codec_data*
|
||||
|
||||
ib_0.sf = stream->streamfile;
|
||||
ib_0.offset = stream->offset;
|
||||
ib_0.is.buf = ib_0.buf;
|
||||
bm_setup(&ib_0.is, ib_0.buf, 0); // filled later
|
||||
|
||||
ok = ealayer3_parse_frame(data, num_stream, &ib_0, &eaf_0);
|
||||
if (!ok) goto fail;
|
||||
@ -199,7 +199,7 @@ int mpeg_custom_parse_frame_ealayer3(VGMSTREAMCHANNEL* stream, mpeg_codec_data*
|
||||
|
||||
ib_1.sf = stream->streamfile;
|
||||
ib_1.offset = stream->offset;
|
||||
ib_1.is.buf = ib_1.buf;
|
||||
bm_setup(&ib_1.is, ib_1.buf, 0); // filled later
|
||||
|
||||
ok = ealayer3_parse_frame(data, num_stream, &ib_1, &eaf_1);
|
||||
if (!ok) goto fail;
|
||||
@ -222,12 +222,12 @@ int mpeg_custom_parse_frame_ealayer3(VGMSTREAMCHANNEL* stream, mpeg_codec_data*
|
||||
{
|
||||
bitstream_t os = {0};
|
||||
|
||||
init_bitstream(&os, ms->buffer, ms->buffer_size);
|
||||
bm_setup(&os, ms->buffer, ms->buffer_size);
|
||||
|
||||
ok = ealayer3_rebuild_mpeg_frame(&ib_0.is, &eaf_0, &ib_1.is, &eaf_1, &os);
|
||||
if (!ok) goto fail;
|
||||
|
||||
ms->bytes_in_buffer = os.b_off / 8; /* wrote full MPEG frame, hopefully */
|
||||
ms->bytes_in_buffer = bm_pos(&os) / 8; /* wrote full MPEG frame, hopefully */
|
||||
}
|
||||
|
||||
return 1;
|
||||
@ -267,8 +267,8 @@ static void fill_buf(ealayer3_buffer_t* ib, int bits) {
|
||||
|
||||
//;VGM_LOG("filled: %lx + %x (b=%i, m=%i)\n", ib->offset, bytes_size, bits, (mod > 0 ? 8 - mod : 0));
|
||||
|
||||
read_size = read_streamfile(ib->buf + ib->is.bufsize, ib->offset, bytes_size, ib->sf);
|
||||
ib->is.bufsize += read_size;
|
||||
read_size = read_streamfile(ib->buf + ib->is.bufsize, ib->offset, bytes_size, ib->sf); //TODO don't access internals
|
||||
bm_fill(&ib->is, read_size);
|
||||
ib->offset += read_size;
|
||||
ib->leftover_bits = (mod > 0 ? 8 - mod : 0);
|
||||
}
|
||||
@ -309,7 +309,7 @@ static int ealayer3_parse_frame_v1(ealayer3_buffer_t* ib, ealayer3_frame_t* eaf,
|
||||
|
||||
/* read EA-frame V1 header */
|
||||
fill_buf(ib, 8);
|
||||
rb_bits(is, 8,&eaf->v1_pcm_flag);
|
||||
bm_get(is, 8,&eaf->v1_pcm_flag);
|
||||
|
||||
eaf->pre_size = 1; /* 8b */
|
||||
|
||||
@ -331,15 +331,15 @@ static int ealayer3_parse_frame_v1(ealayer3_buffer_t* ib, ealayer3_frame_t* eaf,
|
||||
/* check PCM block */
|
||||
if (eaf->v1_pcm_flag == 0xEE) {
|
||||
fill_buf(ib, 32);
|
||||
rb_bits(is, 16,&eaf->v1_offset_samples); /* PCM block offset in the buffer */
|
||||
rb_bits(is, 16,&eaf->v1_pcm_samples); /* number of PCM samples, can be 0 */
|
||||
bm_get(is, 16,&eaf->v1_offset_samples); /* PCM block offset in the buffer */
|
||||
bm_get(is, 16,&eaf->v1_pcm_samples); /* number of PCM samples, can be 0 */
|
||||
|
||||
eaf->pre_size += 2+2; /* 16b+16b */
|
||||
eaf->pcm_size = (2*eaf->v1_pcm_samples * channels_per_frame);
|
||||
|
||||
if (is_v1b) { /* extra 32b in v1b */
|
||||
fill_buf(ib, 32);
|
||||
rb_bits(is, 32,&eaf->v1_pcm_unknown);
|
||||
bm_get(is, 32,&eaf->v1_pcm_unknown);
|
||||
|
||||
eaf->pre_size += 4; /* 32b */
|
||||
|
||||
@ -363,19 +363,19 @@ static int ealayer3_parse_frame_v2(ealayer3_buffer_t* ib, ealayer3_frame_t* eaf)
|
||||
|
||||
/* read EA-frame V2 header */
|
||||
fill_buf(ib, 16);
|
||||
rb_bits(is, 1,&eaf->v2_extended_flag);
|
||||
rb_bits(is, 1,&eaf->v2_stereo_flag);
|
||||
rb_bits(is, 2,&eaf->v2_reserved);
|
||||
rb_bits(is, 12,&eaf->v2_frame_size);
|
||||
bm_get(is, 1,&eaf->v2_extended_flag);
|
||||
bm_get(is, 1,&eaf->v2_stereo_flag);
|
||||
bm_get(is, 2,&eaf->v2_reserved);
|
||||
bm_get(is, 12,&eaf->v2_frame_size);
|
||||
|
||||
eaf->pre_size = 2; /* 16b */
|
||||
|
||||
if (eaf->v2_extended_flag) {
|
||||
fill_buf(ib, 32);
|
||||
rb_bits(is, 2,&eaf->v2_offset_mode);
|
||||
rb_bits(is, 10,&eaf->v2_offset_samples);
|
||||
rb_bits(is, 10,&eaf->v2_pcm_samples);
|
||||
rb_bits(is, 10,&eaf->v2_common_size);
|
||||
bm_get(is, 2,&eaf->v2_offset_mode);
|
||||
bm_get(is, 10,&eaf->v2_offset_samples);
|
||||
bm_get(is, 10,&eaf->v2_pcm_samples);
|
||||
bm_get(is, 10,&eaf->v2_common_size);
|
||||
|
||||
eaf->pre_size += 4; /* 32b */
|
||||
}
|
||||
@ -423,16 +423,16 @@ static int ealayer3_parse_frame_common(ealayer3_buffer_t* ib, ealayer3_frame_t*
|
||||
static const int channel_table[4] = { 2,2,2, 1 }; /* [channel_mode] */
|
||||
|
||||
bitstream_t* is = &ib->is;
|
||||
off_t start_b_off = is->b_off;
|
||||
off_t start_b_off = bm_pos(is);
|
||||
int i, fill_bits, others_2_bits;
|
||||
|
||||
|
||||
/* read main header */
|
||||
fill_buf(ib, 8);
|
||||
rb_bits(is, 2,&eaf->version_index);
|
||||
rb_bits(is, 2,&eaf->sample_rate_index);
|
||||
rb_bits(is, 2,&eaf->channel_mode);
|
||||
rb_bits(is, 2,&eaf->mode_extension);
|
||||
bm_get(is, 2,&eaf->version_index);
|
||||
bm_get(is, 2,&eaf->sample_rate_index);
|
||||
bm_get(is, 2,&eaf->channel_mode);
|
||||
bm_get(is, 2,&eaf->mode_extension);
|
||||
|
||||
|
||||
/* check empty frame */
|
||||
@ -460,7 +460,7 @@ static int ealayer3_parse_frame_common(ealayer3_buffer_t* ib, ealayer3_frame_t*
|
||||
|
||||
/* read side info */
|
||||
fill_buf(ib, 1);
|
||||
rb_bits(is, 1,&eaf->granule_index);
|
||||
bm_get(is, 1,&eaf->granule_index);
|
||||
|
||||
fill_bits = (eaf->mpeg1 && eaf->granule_index == 1) ? 4 * eaf->channels : 0;
|
||||
fill_bits = fill_bits + (12 + 32 + others_2_bits) * eaf->channels;
|
||||
@ -468,21 +468,21 @@ static int ealayer3_parse_frame_common(ealayer3_buffer_t* ib, ealayer3_frame_t*
|
||||
|
||||
if (eaf->mpeg1 && eaf->granule_index == 1) {
|
||||
for (i = 0; i < eaf->channels; i++) {
|
||||
rb_bits(is, 4,&eaf->scfsi[i]);
|
||||
bm_get(is, 4,&eaf->scfsi[i]);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < eaf->channels; i++) {
|
||||
rb_bits(is, 12,&eaf->main_data_size[i]);
|
||||
bm_get(is, 12,&eaf->main_data_size[i]);
|
||||
/* divided in 47b=32+15 (MPEG1) or 51b=32+19 (MPEG2), arbitrarily */
|
||||
rb_bits(is, 32,&eaf->others_1[i]);
|
||||
rb_bits(is, others_2_bits,&eaf->others_2[i]);
|
||||
bm_get(is, 32,&eaf->others_1[i]);
|
||||
bm_get(is, others_2_bits,&eaf->others_2[i]);
|
||||
}
|
||||
|
||||
|
||||
/* derived */
|
||||
eaf->data_offset_b = is->b_off; /* header size + above size */
|
||||
eaf->base_size_b = (is->b_off - start_b_off); /* above size without header */
|
||||
eaf->data_offset_b = bm_pos(is); /* header size + above size */
|
||||
eaf->base_size_b = (bm_pos(is) - start_b_off); /* above size without header */
|
||||
for (i = 0; i < eaf->channels; i++) {
|
||||
eaf->data_size_b += eaf->main_data_size[i]; /* can be 0, meaning a micro EA-frame */
|
||||
}
|
||||
@ -490,7 +490,7 @@ static int ealayer3_parse_frame_common(ealayer3_buffer_t* ib, ealayer3_frame_t*
|
||||
eaf->padding_size_b = 8 - ((eaf->base_size_b+eaf->data_size_b) % 8);
|
||||
|
||||
fill_buf(ib, eaf->data_size_b + eaf->padding_size_b); /* read MPEG data (not PCM block) */
|
||||
is->b_off += eaf->data_size_b + eaf->padding_size_b;
|
||||
bm_skip(is, eaf->data_size_b + eaf->padding_size_b);
|
||||
|
||||
eaf->common_size = (eaf->base_size_b + eaf->data_size_b + eaf->padding_size_b)/8;
|
||||
|
||||
@ -542,55 +542,55 @@ static int ealayer3_rebuild_mpeg_frame(bitstream_t* is_0, ealayer3_frame_t* eaf_
|
||||
#endif
|
||||
|
||||
/* write MPEG1/2 frame header */
|
||||
wb_bits(os, 11, 0x7FF); /* sync */
|
||||
wb_bits(os, 2, eaf_0->version_index);
|
||||
wb_bits(os, 2, 0x01); /* layer III index */
|
||||
wb_bits(os, 1, 1); /* "no CRC" flag */
|
||||
wb_bits(os, 4, expected_bitrate_index);
|
||||
wb_bits(os, 2, eaf_0->sample_rate_index);
|
||||
wb_bits(os, 1, 0); /* padding */
|
||||
wb_bits(os, 1, 0); /* private */
|
||||
wb_bits(os, 2, eaf_0->channel_mode);
|
||||
wb_bits(os, 2, eaf_0->mode_extension);
|
||||
wb_bits(os, 1, 1); /* copyrighted */
|
||||
wb_bits(os, 1, 1); /* original */
|
||||
wb_bits(os, 2, 0); /* emphasis */
|
||||
bm_put(os, 11, 0x7FF); /* sync */
|
||||
bm_put(os, 2, eaf_0->version_index);
|
||||
bm_put(os, 2, 0x01); /* layer III index */
|
||||
bm_put(os, 1, 1); /* "no CRC" flag */
|
||||
bm_put(os, 4, expected_bitrate_index);
|
||||
bm_put(os, 2, eaf_0->sample_rate_index);
|
||||
bm_put(os, 1, 0); /* padding */
|
||||
bm_put(os, 1, 0); /* private */
|
||||
bm_put(os, 2, eaf_0->channel_mode);
|
||||
bm_put(os, 2, eaf_0->mode_extension);
|
||||
bm_put(os, 1, 1); /* copyrighted */
|
||||
bm_put(os, 1, 1); /* original */
|
||||
bm_put(os, 2, 0); /* emphasis */
|
||||
|
||||
if (eaf_0->mpeg1) {
|
||||
int private_bits = (eaf_0->channels==1 ? 5 : 3);
|
||||
|
||||
/* write MPEG1 side info */
|
||||
wb_bits(os, 9, 0); /* main data start (no bit reservoir) */
|
||||
wb_bits(os, private_bits, 0);
|
||||
bm_put(os, 9, 0); /* main data start (no bit reservoir) */
|
||||
bm_put(os, private_bits, 0);
|
||||
|
||||
for (i = 0; i < eaf_1->channels; i++) {
|
||||
wb_bits(os, 4, eaf_1->scfsi[i]); /* saved in granule1 only */
|
||||
bm_put(os, 4, eaf_1->scfsi[i]); /* saved in granule1 only */
|
||||
}
|
||||
for (i = 0; i < eaf_0->channels; i++) { /* granule0 */
|
||||
wb_bits(os, 12, eaf_0->main_data_size[i]);
|
||||
wb_bits(os, 32, eaf_0->others_1[i]);
|
||||
wb_bits(os, 47-32, eaf_0->others_2[i]);
|
||||
bm_put(os, 12, eaf_0->main_data_size[i]);
|
||||
bm_put(os, 32, eaf_0->others_1[i]);
|
||||
bm_put(os, 47-32, eaf_0->others_2[i]);
|
||||
}
|
||||
for (i = 0; i < eaf_1->channels; i++) { /* granule1 */
|
||||
wb_bits(os, 12, eaf_1->main_data_size[i]);
|
||||
wb_bits(os, 32, eaf_1->others_1[i]);
|
||||
wb_bits(os, 47-32, eaf_1->others_2[i]);
|
||||
bm_put(os, 12, eaf_1->main_data_size[i]);
|
||||
bm_put(os, 32, eaf_1->others_1[i]);
|
||||
bm_put(os, 47-32, eaf_1->others_2[i]);
|
||||
}
|
||||
|
||||
/* write MPEG1 main data */
|
||||
is_0->b_off = eaf_0->data_offset_b;
|
||||
bm_set(is_0, eaf_0->data_offset_b);
|
||||
for (i = 0; i < eaf_0->channels; i++) { /* granule0 */
|
||||
for (j = 0; j < eaf_0->main_data_size[i]; j++) {
|
||||
rb_bits(is_0, 1, &c);
|
||||
wb_bits(os, 1, c);
|
||||
bm_get(is_0, 1, &c);
|
||||
bm_put(os, 1, c);
|
||||
}
|
||||
}
|
||||
|
||||
is_1->b_off = eaf_1->data_offset_b;
|
||||
bm_set(is_1, eaf_1->data_offset_b);
|
||||
for (i = 0; i < eaf_1->channels; i++) { /* granule1 */
|
||||
for (j = 0; j < eaf_1->main_data_size[i]; j++) {
|
||||
rb_bits(is_1, 1, &c);
|
||||
wb_bits(os, 1, c);
|
||||
bm_get(is_1, 1, &c);
|
||||
bm_put(os, 1, c);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -598,43 +598,42 @@ static int ealayer3_rebuild_mpeg_frame(bitstream_t* is_0, ealayer3_frame_t* eaf_
|
||||
int private_bits = (eaf_0->channels==1 ? 1 : 2);
|
||||
|
||||
/* write MPEG2 side info */
|
||||
wb_bits(os, 8, 0); /* main data start (no bit reservoir) */
|
||||
wb_bits(os, private_bits, 0);
|
||||
bm_put(os, 8, 0); /* main data start (no bit reservoir) */
|
||||
bm_put(os, private_bits, 0);
|
||||
|
||||
for (i = 0; i < eaf_0->channels; i++) {
|
||||
wb_bits(os, 12, eaf_0->main_data_size[i]);
|
||||
wb_bits(os, 32, eaf_0->others_1[i]);
|
||||
wb_bits(os, 51-32, eaf_0->others_2[i]);
|
||||
bm_put(os, 12, eaf_0->main_data_size[i]);
|
||||
bm_put(os, 32, eaf_0->others_1[i]);
|
||||
bm_put(os, 51-32, eaf_0->others_2[i]);
|
||||
}
|
||||
|
||||
/* write MPEG2 main data */
|
||||
is_0->b_off = eaf_0->data_offset_b;
|
||||
bm_set(is_0, eaf_0->data_offset_b);
|
||||
for (i = 0; i < eaf_0->channels; i++) {
|
||||
for (j = 0; j < eaf_0->main_data_size[i]; j++) {
|
||||
rb_bits(is_0, 1, &c);
|
||||
wb_bits(os, 1, c);
|
||||
bm_get(is_0, 1, &c);
|
||||
bm_put(os, 1, c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* align to closest 8b */
|
||||
if (os->b_off % 8) {
|
||||
int align_bits = 8 - (os->b_off % 8);
|
||||
wb_bits(os, align_bits, 0);
|
||||
if (bm_pos(os) % 8) {
|
||||
int align_bits = 8 - (bm_pos(os) % 8);
|
||||
bm_put(os, align_bits, 0);
|
||||
}
|
||||
|
||||
|
||||
if (os->b_off/8 > expected_frame_size) {
|
||||
if (bm_pos(os) / 8 > expected_frame_size) {
|
||||
/* bit reservoir! shouldn't happen with free bitrate, otherwise it's hard to fix as needs complex buffering/calcs */
|
||||
VGM_LOG("EAL3: written 0x%x but expected less than 0x%x\n", (uint32_t)(os->b_off/8), expected_frame_size);
|
||||
VGM_LOG("EAL3: written 0x%x but expected less than 0x%x\n", (uint32_t)(bm_pos(os) / 8), expected_frame_size);
|
||||
}
|
||||
else {
|
||||
/* fill ancillary data (should be ignored, but 0x00 seems to improve mpg123's free bitrate detection) */
|
||||
memset(os->buf + os->b_off/8, 0x00, expected_frame_size - os->b_off/8);
|
||||
memset(os->buf + bm_pos(os) / 8, 0x00, expected_frame_size - bm_pos(os) / 8);
|
||||
}
|
||||
|
||||
os->b_off = expected_frame_size*8;
|
||||
|
||||
bm_set(os, expected_frame_size * 8);
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
@ -835,7 +834,7 @@ static int ealayer3_skip_data(VGMSTREAMCHANNEL* stream, mpeg_codec_data* data, i
|
||||
for (i = 0; i < skips; i++) {
|
||||
ib.sf = stream->streamfile;
|
||||
ib.offset = stream->offset;
|
||||
ib.is.buf = ib.buf;
|
||||
bm_setup(&ib.is, ib.buf, 0); // filled later
|
||||
|
||||
ok = ealayer3_parse_frame(data, num_stream, &ib, &eaf);
|
||||
if (!ok) goto fail;
|
||||
|
@ -97,6 +97,7 @@ static const char* extension_list[] = {
|
||||
"bar",
|
||||
"bcstm",
|
||||
"bcwav",
|
||||
"bcv", //txth/reserved [The Bigs (PSP)]
|
||||
"bd3",
|
||||
"bdsp",
|
||||
"bfstm",
|
||||
@ -998,7 +999,6 @@ static const meta_info meta_info_list[] = {
|
||||
{meta_DSP_MSS, "Double DSP header stereo by .mss extension"},
|
||||
{meta_DSP_GCM, "Double DSP header stereo by .gcm extension"},
|
||||
{meta_IDSP_TT, "Traveller's Tales IDSP header"},
|
||||
{meta_RSTM_SPM, "Nintendo RSTM header (brstmspm)"},
|
||||
{meta_RAW_PCM, "PC .raw raw header"},
|
||||
{meta_PS2_VAGi, "Sony VAGi header"},
|
||||
{meta_PS2_VAGp, "Sony VAGp header"},
|
||||
@ -1122,7 +1122,6 @@ static const meta_info meta_info_list[] = {
|
||||
{meta_PS2_P2BT, "Pop'n'Music 7 Header"},
|
||||
{meta_PS2_GBTS, "Pop'n'Music 9 Header"},
|
||||
{meta_NGC_DSP_IADP, "IADP Header"},
|
||||
{meta_RSTM_shrunken, "Nintendo RSTM header, corrupted by Atlus"},
|
||||
{meta_RIFF_WAVE_MWV, "RIFF WAVE header with .mwv flavoring"},
|
||||
{meta_FFCC_STR, "Final Fantasy: Crystal Chronicles STR header"},
|
||||
{meta_SAT_BAKA, "Konami BAKA header"},
|
||||
|
@ -84,7 +84,7 @@
|
||||
<ItemGroup>
|
||||
<ClInclude Include="coding\hca_decoder_clhca.h" />
|
||||
<ClInclude Include="coding\ice_decoder_icelib.h" />
|
||||
<ClInclude Include="coding\mpeg_bitreader.h" />
|
||||
<ClInclude Include="util\bitstream_msb.h" />
|
||||
<ClInclude Include="coding\mpeg_decoder.h" />
|
||||
<ClInclude Include="coding\vorbis_bitreader.h" />
|
||||
<ClInclude Include="coding\vorbis_custom_data_fsb.h" />
|
||||
@ -105,6 +105,7 @@
|
||||
<ClInclude Include="meta\adx_keys.h" />
|
||||
<ClInclude Include="meta\aax_utf.h" />
|
||||
<ClInclude Include="meta\9tav_streamfile.h" />
|
||||
<ClInclude Include="meta\ahx_keys.h" />
|
||||
<ClInclude Include="meta\aix_streamfile.h" />
|
||||
<ClInclude Include="meta\awc_xma_streamfile.h" />
|
||||
<ClInclude Include="meta\bar_streamfile.h" />
|
||||
@ -172,6 +173,7 @@
|
||||
<ClInclude Include="layout\layout.h" />
|
||||
<ClInclude Include="util\chunks.h" />
|
||||
<ClInclude Include="util\cri_utf.h" />
|
||||
<ClInclude Include="util\cri_keys.h" />
|
||||
<ClInclude Include="util\endianness.h" />
|
||||
<ClInclude Include="util\log.h" />
|
||||
<ClInclude Include="util\m2_psb.h" />
|
||||
@ -736,6 +738,7 @@
|
||||
<ClCompile Include="layout\blocked_xvas.c" />
|
||||
<ClCompile Include="util\chunks.c" />
|
||||
<ClCompile Include="util\cri_utf.c" />
|
||||
<ClCompile Include="util\cri_keys.c" />
|
||||
<ClCompile Include="util\log.c" />
|
||||
<ClCompile Include="util\m2_psb.c" />
|
||||
<ClCompile Include="util\miniz.c" />
|
||||
|
@ -80,6 +80,9 @@
|
||||
<ClInclude Include="meta\9tav_streamfile.h">
|
||||
<Filter>meta\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="meta\ahx_keys.h">
|
||||
<Filter>meta\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="meta\aix_streamfile.h">
|
||||
<Filter>meta\Header Files</Filter>
|
||||
</ClInclude>
|
||||
@ -272,8 +275,8 @@
|
||||
<ClInclude Include="coding\hca_decoder_icelib.h">
|
||||
<Filter>coding\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="coding\mpeg_bitreader.h">
|
||||
<Filter>coding\Header Files</Filter>
|
||||
<ClInclude Include="util\bitstream_msb.h">
|
||||
<Filter>util\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="coding\mpeg_decoder.h">
|
||||
<Filter>coding\Header Files</Filter>
|
||||
@ -317,6 +320,9 @@
|
||||
<ClInclude Include="util\cri_utf.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="util\cri_keys.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="util\endianness.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
@ -1990,6 +1996,9 @@
|
||||
<ClCompile Include="util\cri_utf.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="util\cri_keys.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="util\log.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "meta.h"
|
||||
#include "adx_keys.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../util/cri_keys.h"
|
||||
|
||||
|
||||
#ifdef VGM_DEBUG_OUTPUT
|
||||
@ -280,39 +281,32 @@ static int find_adx_key(STREAMFILE* sf, uint8_t type, uint16_t *xor_start, uint1
|
||||
key_size = read_key_file(keybuf, sizeof(keybuf), sf);
|
||||
|
||||
if (key_size > 0) {
|
||||
int is_ascii = 0;
|
||||
int is_keystring = 0;
|
||||
|
||||
/* keystrings should be ASCII, also needed to tell apart 0x06 strings from derived keys */
|
||||
if (type == 8) {
|
||||
is_ascii = 1;
|
||||
for (i = 0; i < key_size; i++) {
|
||||
if (keybuf[i] < 0x20 || keybuf[i] > 0x7f) {
|
||||
is_ascii = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
is_keystring = cri_key8_valid_keystring(keybuf, key_size);
|
||||
}
|
||||
|
||||
if (key_size == 0x06 && !is_ascii) {
|
||||
if (key_size == 0x06 && !is_keystring) {
|
||||
*xor_start = get_u16be(keybuf + 0x00);
|
||||
*xor_mult = get_u16be(keybuf + 0x02);
|
||||
*xor_add = get_u16be(keybuf + 0x04);
|
||||
return 1;
|
||||
}
|
||||
else if (type == 8 && is_ascii) {
|
||||
else if (type == 8 && is_keystring) {
|
||||
const char* keystring = (const char*)keybuf;
|
||||
derive_adx_key8(keystring, xor_start, xor_mult, xor_add);
|
||||
cri_key8_derive(keystring, xor_start, xor_mult, xor_add);
|
||||
return 1;
|
||||
}
|
||||
else if (type == 9 && key_size == 0x08) {
|
||||
uint64_t keycode = get_u64be(keybuf);
|
||||
derive_adx_key9(keycode, subkey, xor_start, xor_mult, xor_add);
|
||||
cri_key9_derive(keycode, subkey, xor_start, xor_mult, xor_add);
|
||||
return 1;
|
||||
}
|
||||
else if (type == 9 && key_size == 0x08+0x02) {
|
||||
uint64_t file_keycode = get_u64be(keybuf+0x00);
|
||||
uint16_t file_subkey = get_u16be(keybuf+0x08);
|
||||
derive_adx_key9(file_keycode, file_subkey, xor_start, xor_mult, xor_add);
|
||||
cri_key9_derive(file_keycode, file_subkey, xor_start, xor_mult, xor_add);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@ -438,7 +432,7 @@ static int find_adx_key(STREAMFILE* sf, uint8_t type, uint16_t *xor_start, uint1
|
||||
#ifdef ADX_BRUTEFORCE
|
||||
if (buf) {
|
||||
keycode = get_u64be(buf + key_id);
|
||||
derive_adx_key9(keycode, subkey, &key_xor, &key_mul, &key_add);
|
||||
cri_key9_derive(keycode, subkey, &key_xor, &key_mul, &key_add);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
@ -450,11 +444,11 @@ static int find_adx_key(STREAMFILE* sf, uint8_t type, uint16_t *xor_start, uint1
|
||||
key_add = keys[key_id].add;
|
||||
}
|
||||
else if (type == 8 && keys[key_id].key8) {
|
||||
derive_adx_key8(keys[key_id].key8, &key_xor, &key_mul, &key_add);
|
||||
cri_key8_derive(keys[key_id].key8, &key_xor, &key_mul, &key_add);
|
||||
}
|
||||
else if (type == 9 && keys[key_id].key9) {
|
||||
uint64_t keycode = keys[key_id].key9;
|
||||
derive_adx_key9(keycode, subkey, &key_xor, &key_mul, &key_add);
|
||||
cri_key9_derive(keycode, subkey, &key_xor, &key_mul, &key_add);
|
||||
}
|
||||
else {
|
||||
VGM_LOG("ADX: incorrectly defined key id=%i\n", key_id);
|
||||
@ -474,13 +468,13 @@ static int find_adx_key(STREAMFILE* sf, uint8_t type, uint16_t *xor_start, uint1
|
||||
mul = keys[key_id].mult;
|
||||
add = keys[key_id].add;
|
||||
if (type == 8 && keys[key_id].key8) {
|
||||
derive_adx_key8(keys[key_id].key8, &test_xor, &test_mul, &test_add);
|
||||
cri_key8_derive(keys[key_id].key8, &test_xor, &test_mul, &test_add);
|
||||
VGM_LOG("key8: pre=%04x %04x %04x vs calc=%04x %04x %04x = %s (\"%s\")\n",
|
||||
xor,mul,add, test_xor,test_mul,test_add,
|
||||
xor==test_xor && mul==test_mul && add==test_add ? "ok" : "ko", keys[key_id].key8);
|
||||
}
|
||||
else if (type == 9 && keys[key_id].key9) {
|
||||
derive_adx_key9(keys[key_id].key9, subkey, &test_xor, &test_mul, &test_add);
|
||||
cri_key9_derive(keys[key_id].key9, subkey, &test_xor, &test_mul, &test_add);
|
||||
VGM_LOG("key9: pre=%04x %04x %04x vs calc=%04x %04x %04x = %s (%"PRIu64")\n",
|
||||
xor,mul,add, test_xor,test_mul,test_add,
|
||||
xor==test_xor && mul==test_mul && add==test_add ? "ok" : "ko", keys[key_id].key9);
|
||||
|
@ -1,6 +1,8 @@
|
||||
#ifndef _ADX_KEYS_H_
|
||||
#define _ADX_KEYS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct {
|
||||
uint16_t start, mult, add; /* XOR values derived from the actual key */
|
||||
@ -53,7 +55,7 @@ static const adxkey_info adxkey8_list[] = {
|
||||
{0x55b7,0x6191,0x5a77, "morio",0},
|
||||
|
||||
/* Amagami (PS2) [Enterbrain] */
|
||||
{0x5a17,0x509f,0x5bfd, "mituba",0}, /* also AHX key */
|
||||
{0x5a17,0x509f,0x5bfd, "mituba",0},
|
||||
|
||||
/* Yamasa Digi Portable: Matsuri no Tatsujin (PSP) [Yamasa] */
|
||||
{0x4c01,0x549d,0x676f, "7fa0xB9tw3",0},
|
||||
@ -122,7 +124,7 @@ static const adxkey_info adxkey8_list[] = {
|
||||
{0x4c73,0x4d8d,0x5827, "URABOKU-penguin",0},
|
||||
|
||||
/* StormLover!! (PSP), StormLover Kai!! (PSP) [Vridge] */
|
||||
{0x5a11,0x67e5,0x6751, "HEXDPFMDKPQW",0}, /* unknown AHX key */
|
||||
{0x5a11,0x67e5,0x6751, "HEXDPFMDKPQW",0},
|
||||
|
||||
/* Sora no Otoshimono: DokiDoki Summer Vacation (PSP) [Kadokawa Shoten] */
|
||||
{0x5e75,0x4a89,0x4c61, "funen-gomi",0},
|
||||
@ -131,25 +133,26 @@ static const adxkey_info adxkey8_list[] = {
|
||||
{0x64ab,0x5297,0x632f, "sonic",0},
|
||||
|
||||
/* Lucky Star: Net Idol Meister (PSP) [Vridge, Kadokawa Shoten] */
|
||||
{0x4d81,0x5243,0x58c7, "JJOLIFJLE",0}, /* unknown AHX key */
|
||||
/* Baka to Test to Shoukanjuu Portable (PSP) */
|
||||
{0x4d81,0x5243,0x58c7, "JJOLIFJLE",0},
|
||||
|
||||
/* Ishin Renka: Ryouma Gaiden (PSP) [Vridge] */
|
||||
{0x54d1,0x526d,0x5e8b, "LQAFJOIEJ",0}, /* unknown AHX key */
|
||||
{0x54d1,0x526d,0x5e8b, "LQAFJOIEJ",0},
|
||||
|
||||
/* Lucky Star: Ryouou Gakuen Outousai Portable (PSP) [Vridge] */
|
||||
{0x4d05,0x663b,0x6343, "IUNOIRU",0}, /* unknown AHX key */
|
||||
{0x4d05,0x663b,0x6343, "IUNOIRU",0},
|
||||
|
||||
/* Marriage Royale: Prism Story (PSP) [Vridge] */
|
||||
{0x40a9,0x46b1,0x62ad, "ROYMAR",0}, /* unknown AHX key */
|
||||
{0x40a9,0x46b1,0x62ad, "ROYMAR",0},
|
||||
|
||||
/* Nogizaka Haruka no Himitsu: Doujinshi Hajimemashita (PSP) [Vridge] */
|
||||
{0x4609,0x671f,0x4b65, "CLKMEOUHFLIE",0}, /* unknown AHX key */
|
||||
{0x4609,0x671f,0x4b65, "CLKMEOUHFLIE",0},
|
||||
|
||||
/* Slotter Mania P: Mach Go Go Go III (PSP) [Dorart] */
|
||||
{0x41ef,0x463d,0x5507, "SGGK",0},
|
||||
|
||||
/* Nichijou: Uchuujin (PSP) [Vridge] */
|
||||
{0x4369,0x486d,0x5461, "LJLOUHIU787",0}, /* unknown AHX key */
|
||||
{0x4369,0x486d,0x5461, "LJLOUHIU787",0},
|
||||
|
||||
/* R-15 Portable (PSP) [Kadokawa Shoten] */
|
||||
{0x6809,0x5fd5,0x5bb1, "R-15(Heart)Love",0},
|
||||
@ -158,7 +161,7 @@ static const adxkey_info adxkey8_list[] = {
|
||||
{0x5c33,0x4133,0x4ce7, "bi88a#fas",0},
|
||||
|
||||
/* StormLover Natsu Koi!! (PSP) [Vridge] */
|
||||
{0x4133,0x5a01,0x5723, "LIKDFJUIDJOQ",0}, /* unknown AHX key */
|
||||
{0x4133,0x5a01,0x5723, "LIKDFJUIDJOQ",0},
|
||||
|
||||
/* Shounen Onmyouji: Tsubasa yo Ima, Sora e Kaere (PS2) [Kadokawa Shoten] */
|
||||
{0x55d9,0x46d3,0x5b01, "SONMYOJI",0},
|
||||
@ -272,129 +275,4 @@ static const adxkey_info adxkey9_list[] = {
|
||||
static const int adxkey8_list_count = sizeof(adxkey8_list) / sizeof(adxkey8_list[0]);
|
||||
static const int adxkey9_list_count = sizeof(adxkey9_list) / sizeof(adxkey9_list[0]);
|
||||
|
||||
|
||||
/* preloaded list used to derive keystrings from ADX_Decoder, found in executables (see VGAudio for how to calculate) */
|
||||
static const uint16_t key8_primes[0x400] = {
|
||||
0x401B,0x4021,0x4025,0x402B,0x4031,0x403F,0x4043,0x4045,0x405D,0x4061,0x4067,0x406D,0x4087,0x4091,0x40A3,0x40A9,
|
||||
0x40B1,0x40B7,0x40BD,0x40DB,0x40DF,0x40EB,0x40F7,0x40F9,0x4109,0x410B,0x4111,0x4115,0x4121,0x4133,0x4135,0x413B,
|
||||
0x413F,0x4159,0x4165,0x416B,0x4177,0x417B,0x4193,0x41AB,0x41B7,0x41BD,0x41BF,0x41CB,0x41E7,0x41EF,0x41F3,0x41F9,
|
||||
0x4205,0x4207,0x4219,0x421F,0x4223,0x4229,0x422F,0x4243,0x4253,0x4255,0x425B,0x4261,0x4273,0x427D,0x4283,0x4285,
|
||||
0x4289,0x4291,0x4297,0x429D,0x42B5,0x42C5,0x42CB,0x42D3,0x42DD,0x42E3,0x42F1,0x4307,0x430F,0x431F,0x4325,0x4327,
|
||||
0x4333,0x4337,0x4339,0x434F,0x4357,0x4369,0x438B,0x438D,0x4393,0x43A5,0x43A9,0x43AF,0x43B5,0x43BD,0x43C7,0x43CF,
|
||||
0x43E1,0x43E7,0x43EB,0x43ED,0x43F1,0x43F9,0x4409,0x440B,0x4417,0x4423,0x4429,0x443B,0x443F,0x4445,0x444B,0x4451,
|
||||
0x4453,0x4459,0x4465,0x446F,0x4483,0x448F,0x44A1,0x44A5,0x44AB,0x44AD,0x44BD,0x44BF,0x44C9,0x44D7,0x44DB,0x44F9,
|
||||
0x44FB,0x4505,0x4511,0x4513,0x452B,0x4531,0x4541,0x4549,0x4553,0x4555,0x4561,0x4577,0x457D,0x457F,0x458F,0x45A3,
|
||||
0x45AD,0x45AF,0x45BB,0x45C7,0x45D9,0x45E3,0x45EF,0x45F5,0x45F7,0x4601,0x4603,0x4609,0x4613,0x4625,0x4627,0x4633,
|
||||
0x4639,0x463D,0x4643,0x4645,0x465D,0x4679,0x467B,0x467F,0x4681,0x468B,0x468D,0x469D,0x46A9,0x46B1,0x46C7,0x46C9,
|
||||
0x46CF,0x46D3,0x46D5,0x46DF,0x46E5,0x46F9,0x4705,0x470F,0x4717,0x4723,0x4729,0x472F,0x4735,0x4739,0x474B,0x474D,
|
||||
0x4751,0x475D,0x476F,0x4771,0x477D,0x4783,0x4787,0x4789,0x4799,0x47A5,0x47B1,0x47BF,0x47C3,0x47CB,0x47DD,0x47E1,
|
||||
0x47ED,0x47FB,0x4801,0x4807,0x480B,0x4813,0x4819,0x481D,0x4831,0x483D,0x4847,0x4855,0x4859,0x485B,0x486B,0x486D,
|
||||
0x4879,0x4897,0x489B,0x48A1,0x48B9,0x48CD,0x48E5,0x48EF,0x48F7,0x4903,0x490D,0x4919,0x491F,0x492B,0x4937,0x493D,
|
||||
0x4945,0x4955,0x4963,0x4969,0x496D,0x4973,0x4997,0x49AB,0x49B5,0x49D3,0x49DF,0x49E1,0x49E5,0x49E7,0x4A03,0x4A0F,
|
||||
0x4A1D,0x4A23,0x4A39,0x4A41,0x4A45,0x4A57,0x4A5D,0x4A6B,0x4A7D,0x4A81,0x4A87,0x4A89,0x4A8F,0x4AB1,0x4AC3,0x4AC5,
|
||||
0x4AD5,0x4ADB,0x4AED,0x4AEF,0x4B07,0x4B0B,0x4B0D,0x4B13,0x4B1F,0x4B25,0x4B31,0x4B3B,0x4B43,0x4B49,0x4B59,0x4B65,
|
||||
0x4B6D,0x4B77,0x4B85,0x4BAD,0x4BB3,0x4BB5,0x4BBB,0x4BBF,0x4BCB,0x4BD9,0x4BDD,0x4BDF,0x4BE3,0x4BE5,0x4BE9,0x4BF1,
|
||||
0x4BF7,0x4C01,0x4C07,0x4C0D,0x4C0F,0x4C15,0x4C1B,0x4C21,0x4C2D,0x4C33,0x4C4B,0x4C55,0x4C57,0x4C61,0x4C67,0x4C73,
|
||||
0x4C79,0x4C7F,0x4C8D,0x4C93,0x4C99,0x4CCD,0x4CE1,0x4CE7,0x4CF1,0x4CF3,0x4CFD,0x4D05,0x4D0F,0x4D1B,0x4D27,0x4D29,
|
||||
0x4D2F,0x4D33,0x4D41,0x4D51,0x4D59,0x4D65,0x4D6B,0x4D81,0x4D83,0x4D8D,0x4D95,0x4D9B,0x4DB1,0x4DB3,0x4DC9,0x4DCF,
|
||||
0x4DD7,0x4DE1,0x4DED,0x4DF9,0x4DFB,0x4E05,0x4E0B,0x4E17,0x4E19,0x4E1D,0x4E2B,0x4E35,0x4E37,0x4E3D,0x4E4F,0x4E53,
|
||||
0x4E5F,0x4E67,0x4E79,0x4E85,0x4E8B,0x4E91,0x4E95,0x4E9B,0x4EA1,0x4EAF,0x4EB3,0x4EB5,0x4EC1,0x4ECD,0x4ED1,0x4ED7,
|
||||
0x4EE9,0x4EFB,0x4F07,0x4F09,0x4F19,0x4F25,0x4F2D,0x4F3F,0x4F49,0x4F63,0x4F67,0x4F6D,0x4F75,0x4F7B,0x4F81,0x4F85,
|
||||
0x4F87,0x4F91,0x4FA5,0x4FA9,0x4FAF,0x4FB7,0x4FBB,0x4FCF,0x4FD9,0x4FDB,0x4FFD,0x4FFF,0x5003,0x501B,0x501D,0x5029,
|
||||
0x5035,0x503F,0x5045,0x5047,0x5053,0x5071,0x5077,0x5083,0x5093,0x509F,0x50A1,0x50B7,0x50C9,0x50D5,0x50E3,0x50ED,
|
||||
0x50EF,0x50FB,0x5107,0x510B,0x510D,0x5111,0x5117,0x5123,0x5125,0x5135,0x5147,0x5149,0x5171,0x5179,0x5189,0x518F,
|
||||
0x5197,0x51A1,0x51A3,0x51A7,0x51B9,0x51C1,0x51CB,0x51D3,0x51DF,0x51E3,0x51F5,0x51F7,0x5209,0x5213,0x5215,0x5219,
|
||||
0x521B,0x521F,0x5227,0x5243,0x5245,0x524B,0x5261,0x526D,0x5273,0x5281,0x5293,0x5297,0x529D,0x52A5,0x52AB,0x52B1,
|
||||
0x52BB,0x52C3,0x52C7,0x52C9,0x52DB,0x52E5,0x52EB,0x52FF,0x5315,0x531D,0x5323,0x5341,0x5345,0x5347,0x534B,0x535D,
|
||||
0x5363,0x5381,0x5383,0x5387,0x538F,0x5395,0x5399,0x539F,0x53AB,0x53B9,0x53DB,0x53E9,0x53EF,0x53F3,0x53F5,0x53FB,
|
||||
0x53FF,0x540D,0x5411,0x5413,0x5419,0x5435,0x5437,0x543B,0x5441,0x5449,0x5453,0x5455,0x545F,0x5461,0x546B,0x546D,
|
||||
0x5471,0x548F,0x5491,0x549D,0x54A9,0x54B3,0x54C5,0x54D1,0x54DF,0x54E9,0x54EB,0x54F7,0x54FD,0x5507,0x550D,0x551B,
|
||||
0x5527,0x552B,0x5539,0x553D,0x554F,0x5551,0x555B,0x5563,0x5567,0x556F,0x5579,0x5585,0x5597,0x55A9,0x55B1,0x55B7,
|
||||
0x55C9,0x55D9,0x55E7,0x55ED,0x55F3,0x55FD,0x560B,0x560F,0x5615,0x5617,0x5623,0x562F,0x5633,0x5639,0x563F,0x564B,
|
||||
0x564D,0x565D,0x565F,0x566B,0x5671,0x5675,0x5683,0x5689,0x568D,0x568F,0x569B,0x56AD,0x56B1,0x56D5,0x56E7,0x56F3,
|
||||
0x56FF,0x5701,0x5705,0x5707,0x570B,0x5713,0x571F,0x5723,0x5747,0x574D,0x575F,0x5761,0x576D,0x5777,0x577D,0x5789,
|
||||
0x57A1,0x57A9,0x57AF,0x57B5,0x57C5,0x57D1,0x57D3,0x57E5,0x57EF,0x5803,0x580D,0x580F,0x5815,0x5827,0x582B,0x582D,
|
||||
0x5855,0x585B,0x585D,0x586D,0x586F,0x5873,0x587B,0x588D,0x5897,0x58A3,0x58A9,0x58AB,0x58B5,0x58BD,0x58C1,0x58C7,
|
||||
0x58D3,0x58D5,0x58DF,0x58F1,0x58F9,0x58FF,0x5903,0x5917,0x591B,0x5921,0x5945,0x594B,0x594D,0x5957,0x595D,0x5975,
|
||||
0x597B,0x5989,0x5999,0x599F,0x59B1,0x59B3,0x59BD,0x59D1,0x59DB,0x59E3,0x59E9,0x59ED,0x59F3,0x59F5,0x59FF,0x5A01,
|
||||
0x5A0D,0x5A11,0x5A13,0x5A17,0x5A1F,0x5A29,0x5A2F,0x5A3B,0x5A4D,0x5A5B,0x5A67,0x5A77,0x5A7F,0x5A85,0x5A95,0x5A9D,
|
||||
0x5AA1,0x5AA3,0x5AA9,0x5ABB,0x5AD3,0x5AE5,0x5AEF,0x5AFB,0x5AFD,0x5B01,0x5B0F,0x5B19,0x5B1F,0x5B25,0x5B2B,0x5B3D,
|
||||
0x5B49,0x5B4B,0x5B67,0x5B79,0x5B87,0x5B97,0x5BA3,0x5BB1,0x5BC9,0x5BD5,0x5BEB,0x5BF1,0x5BF3,0x5BFD,0x5C05,0x5C09,
|
||||
0x5C0B,0x5C0F,0x5C1D,0x5C29,0x5C2F,0x5C33,0x5C39,0x5C47,0x5C4B,0x5C4D,0x5C51,0x5C6F,0x5C75,0x5C77,0x5C7D,0x5C87,
|
||||
0x5C89,0x5CA7,0x5CBD,0x5CBF,0x5CC3,0x5CC9,0x5CD1,0x5CD7,0x5CDD,0x5CED,0x5CF9,0x5D05,0x5D0B,0x5D13,0x5D17,0x5D19,
|
||||
0x5D31,0x5D3D,0x5D41,0x5D47,0x5D4F,0x5D55,0x5D5B,0x5D65,0x5D67,0x5D6D,0x5D79,0x5D95,0x5DA3,0x5DA9,0x5DAD,0x5DB9,
|
||||
0x5DC1,0x5DC7,0x5DD3,0x5DD7,0x5DDD,0x5DEB,0x5DF1,0x5DFD,0x5E07,0x5E0D,0x5E13,0x5E1B,0x5E21,0x5E27,0x5E2B,0x5E2D,
|
||||
0x5E31,0x5E39,0x5E45,0x5E49,0x5E57,0x5E69,0x5E73,0x5E75,0x5E85,0x5E8B,0x5E9F,0x5EA5,0x5EAF,0x5EB7,0x5EBB,0x5ED9,
|
||||
0x5EFD,0x5F09,0x5F11,0x5F27,0x5F33,0x5F35,0x5F3B,0x5F47,0x5F57,0x5F5D,0x5F63,0x5F65,0x5F77,0x5F7B,0x5F95,0x5F99,
|
||||
0x5FA1,0x5FB3,0x5FBD,0x5FC5,0x5FCF,0x5FD5,0x5FE3,0x5FE7,0x5FFB,0x6011,0x6023,0x602F,0x6037,0x6053,0x605F,0x6065,
|
||||
0x606B,0x6073,0x6079,0x6085,0x609D,0x60AD,0x60BB,0x60BF,0x60CD,0x60D9,0x60DF,0x60E9,0x60F5,0x6109,0x610F,0x6113,
|
||||
0x611B,0x612D,0x6139,0x614B,0x6155,0x6157,0x615B,0x616F,0x6179,0x6187,0x618B,0x6191,0x6193,0x619D,0x61B5,0x61C7,
|
||||
0x61C9,0x61CD,0x61E1,0x61F1,0x61FF,0x6209,0x6217,0x621D,0x6221,0x6227,0x623B,0x6241,0x624B,0x6251,0x6253,0x625F,
|
||||
0x6265,0x6283,0x628D,0x6295,0x629B,0x629F,0x62A5,0x62AD,0x62D5,0x62D7,0x62DB,0x62DD,0x62E9,0x62FB,0x62FF,0x6305,
|
||||
0x630D,0x6317,0x631D,0x632F,0x6341,0x6343,0x634F,0x635F,0x6367,0x636D,0x6371,0x6377,0x637D,0x637F,0x63B3,0x63C1,
|
||||
0x63C5,0x63D9,0x63E9,0x63EB,0x63EF,0x63F5,0x6401,0x6403,0x6409,0x6415,0x6421,0x6427,0x642B,0x6439,0x6443,0x6449,
|
||||
0x644F,0x645D,0x6467,0x6475,0x6485,0x648D,0x6493,0x649F,0x64A3,0x64AB,0x64C1,0x64C7,0x64C9,0x64DB,0x64F1,0x64F7,
|
||||
0x64F9,0x650B,0x6511,0x6521,0x652F,0x6539,0x653F,0x654B,0x654D,0x6553,0x6557,0x655F,0x6571,0x657D,0x658D,0x658F,
|
||||
0x6593,0x65A1,0x65A5,0x65AD,0x65B9,0x65C5,0x65E3,0x65F3,0x65FB,0x65FF,0x6601,0x6607,0x661D,0x6629,0x6631,0x663B,
|
||||
0x6641,0x6647,0x664D,0x665B,0x6661,0x6673,0x667D,0x6689,0x668B,0x6695,0x6697,0x669B,0x66B5,0x66B9,0x66C5,0x66CD,
|
||||
0x66D1,0x66E3,0x66EB,0x66F5,0x6703,0x6713,0x6719,0x671F,0x6727,0x6731,0x6737,0x673F,0x6745,0x6751,0x675B,0x676F,
|
||||
0x6779,0x6781,0x6785,0x6791,0x67AB,0x67BD,0x67C1,0x67CD,0x67DF,0x67E5,0x6803,0x6809,0x6811,0x6817,0x682D,0x6839,
|
||||
};
|
||||
|
||||
static void derive_adx_key8(const char* key8, uint16_t* p_start, uint16_t* p_mult, uint16_t* p_add) {
|
||||
size_t key_size;
|
||||
uint16_t start = 0, mult = 0, add = 0;
|
||||
int i;
|
||||
|
||||
if (key8 == NULL || key8[0] == '\0') /* strlen >= 1 */
|
||||
goto end;
|
||||
|
||||
/* calcs as found in exes, though there is some unrolling in the original code */
|
||||
key_size = strlen(key8);
|
||||
start = key8_primes[0x100];
|
||||
mult = key8_primes[0x200];
|
||||
add = key8_primes[0x300];
|
||||
|
||||
for (i = 0; i < key_size; i++) {
|
||||
char c = key8[i];
|
||||
start = key8_primes[start * key8_primes[c + 0x80] % 0x400];
|
||||
mult = key8_primes[mult * key8_primes[c + 0x80] % 0x400];
|
||||
add = key8_primes[add * key8_primes[c + 0x80] % 0x400];
|
||||
}
|
||||
|
||||
end:
|
||||
*p_start = start;
|
||||
*p_mult = mult;
|
||||
*p_add = add;
|
||||
}
|
||||
|
||||
|
||||
static void derive_adx_key9(uint64_t key9, uint16_t subkey, uint16_t* p_start, uint16_t* p_mult, uint16_t* p_add) {
|
||||
uint16_t start = 0, mult = 0, add = 0;
|
||||
|
||||
/* 0 is ignored by CRI's encoder, only from 1..18446744073709551615 */
|
||||
if (key9 == 0)
|
||||
goto end;
|
||||
|
||||
if (subkey) {
|
||||
key9 = key9 * ( ((uint64_t)subkey << 16u) | ((uint16_t)~subkey + 2u) );
|
||||
}
|
||||
|
||||
key9--;
|
||||
start = (int)(((key9 >> 27) & 0x7fff));
|
||||
mult = (int)(((key9 >> 12) & 0x7ffc) | 1);
|
||||
add = (int)(((key9 << 1 ) & 0x7fff) | 1);
|
||||
|
||||
/* alt from ADX_Decoder, probably the same */
|
||||
//start = ((key9 >> 27) & 0x7FFF);
|
||||
//mult = ((key9 >> 12) & 0x7FFC) | 1;
|
||||
//add = ((key9 << 1 ) & 0x7FFE) | 1;
|
||||
//mult |= add << 16;
|
||||
|
||||
end:
|
||||
*p_start = start;
|
||||
*p_mult = mult;
|
||||
*p_add = add;
|
||||
}
|
||||
|
||||
#endif/*_ADX_KEYS_H_*/
|
||||
|
123
src/meta/ahx.c
123
src/meta/ahx.c
@ -1,10 +1,13 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../util.h"
|
||||
#if 0
|
||||
#include "adx_keys.h"
|
||||
#include "ahx_keys.h"
|
||||
#include "../util/cri_keys.h"
|
||||
|
||||
#ifdef VGM_USE_MPEG
|
||||
static int find_ahx_key(STREAMFILE* sf, off_t offset, crikey_t* crikey);
|
||||
#endif
|
||||
|
||||
|
||||
/* AHX - CRI voice format */
|
||||
VGMSTREAM* init_vgmstream_ahx(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
@ -23,7 +26,7 @@ VGMSTREAM* init_vgmstream_ahx(STREAMFILE* sf) {
|
||||
read_u32be(start_offset - 0x04,sf) != 0x29435249) /* ")CRI" */
|
||||
goto fail;
|
||||
|
||||
/* types: 0x10 = AHX for DC with bigger frames, 0x11 = AHX, 0x0N = ADX */
|
||||
/* types: 0x10 = AHX for DC with fixed MPEG frame bits (bigger frames), 0x11 = standard AHX, 0x0N = ADX */
|
||||
type = read_u8(0x04,sf);
|
||||
if (type != 0x10 && type != 0x11) goto fail;
|
||||
|
||||
@ -52,40 +55,13 @@ VGMSTREAM* init_vgmstream_ahx(STREAMFILE* sf) {
|
||||
{
|
||||
#ifdef VGM_USE_MPEG
|
||||
mpeg_custom_config cfg = {0};
|
||||
crikey_t* crikey = &cfg.crikey;
|
||||
|
||||
cfg.encryption = read_u8(0x13,sf); /* 0x08 = keyword encryption */
|
||||
cfg.cri_type = type;
|
||||
cfg.encryption = read_u8(0x13,sf); /* only type 0x08 is known */
|
||||
crikey->type = cfg.encryption;
|
||||
|
||||
if (cfg.encryption) {
|
||||
uint8_t keybuf[0x10+1] = {0}; /* approximate max for keystrings, +1 extra null for keystrings */
|
||||
size_t key_size;
|
||||
|
||||
key_size = read_key_file(keybuf, sizeof(keybuf), sf);
|
||||
if (key_size > 0) {
|
||||
#if 0
|
||||
int i, is_ascii;
|
||||
is_ascii = 1;
|
||||
for (i = 0; i < key_size; i++) {
|
||||
if (keybuf[i] < 0x20 || keybuf[i] > 0x7f) {
|
||||
is_ascii = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (key_size == 0x06 /*&& !is_ascii*/) {
|
||||
cfg.cri_key1 = get_u16be(keybuf + 0x00);
|
||||
cfg.cri_key2 = get_u16be(keybuf + 0x02);
|
||||
cfg.cri_key3 = get_u16be(keybuf + 0x04);
|
||||
}
|
||||
#if 0
|
||||
else if (is_ascii) {
|
||||
const char* keystring = (const char*)keybuf;
|
||||
|
||||
derive_adx_key8(keystring, &cfg.cri_key1, &cfg.cri_key2, &cfg.cri_key3);
|
||||
VGM_LOG("ok: %x, %x, %x\n", cfg.cri_key1, cfg.cri_key2, cfg.cri_key3 );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
find_ahx_key(sf, start_offset, crikey);
|
||||
}
|
||||
|
||||
vgmstream->layout_type = layout_none;
|
||||
@ -104,3 +80,80 @@ fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef VGM_USE_MPEG
|
||||
static int find_ahx_keyfile(STREAMFILE* sf, crikey_t* crikey) {
|
||||
uint8_t keybuf[0x10+1] = {0}; /* approximate max for keystrings, +1 extra null for keystrings */
|
||||
size_t key_size;
|
||||
int is_keystring = 0;
|
||||
|
||||
key_size = read_key_file(keybuf, sizeof(keybuf) - 1, sf);
|
||||
if (key_size <= 0)
|
||||
goto fail;
|
||||
|
||||
|
||||
if (crikey->type == 8) {
|
||||
is_keystring = cri_key8_valid_keystring(keybuf, key_size);
|
||||
}
|
||||
|
||||
if (key_size == 0x06 && !is_keystring) {
|
||||
crikey->key1 = get_u16be(keybuf + 0x00);
|
||||
crikey->key2 = get_u16be(keybuf + 0x02);
|
||||
crikey->key3 = get_u16be(keybuf + 0x04);
|
||||
}
|
||||
else if (crikey->type == 8 && is_keystring) {
|
||||
const char* keystring = (const char*)keybuf;
|
||||
cri_key8_derive(keystring, &crikey->key1, &crikey->key2, &crikey->key3);
|
||||
}
|
||||
else {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int find_ahx_keylist(STREAMFILE* sf, off_t offset, crikey_t* crikey) {
|
||||
int i;
|
||||
int keycount = ahxkey8_list_count;
|
||||
const ahxkey_info* keys = ahxkey8_list;
|
||||
|
||||
|
||||
for (i = 0; i < keycount; i++) {
|
||||
if (crikey->type == 0x08) {
|
||||
cri_key8_derive(keys[i].key8, &crikey->key1, &crikey->key2, &crikey->key3);
|
||||
//;VGM_LOG("AHX: testing %s [%04x %04x %04x]\n", keys[i].key8, crikey->key1, crikey->key2, crikey->key3);
|
||||
}
|
||||
else {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (test_ahx_key(sf, offset, crikey)) {
|
||||
//;VGM_LOG("AHX key found\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int find_ahx_key(STREAMFILE* sf, off_t offset, crikey_t* crikey) {
|
||||
int ok;
|
||||
|
||||
ok = find_ahx_keyfile(sf, crikey);
|
||||
if (ok)
|
||||
return 1;
|
||||
|
||||
ok = find_ahx_keylist(sf, offset, crikey);
|
||||
if (ok)
|
||||
return 1;
|
||||
|
||||
|
||||
crikey->key1 = 0;
|
||||
crikey->key2 = 0;
|
||||
crikey->key3 = 0;
|
||||
vgm_logi("AHX: decryption key not found\n");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
52
src/meta/ahx_keys.h
Normal file
52
src/meta/ahx_keys.h
Normal file
@ -0,0 +1,52 @@
|
||||
#ifndef _AHX_KEYS_H_
|
||||
#define _AHX_KEYS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct {
|
||||
const char* key8; /* keystring used by type 8 encryption */
|
||||
uint64_t key9; /* reserved (not seen) */
|
||||
} ahxkey_info;
|
||||
|
||||
/**
|
||||
* List of known keys, from exes. Generally same as ADX keys as CRI's key init seems shared.
|
||||
*/
|
||||
static const ahxkey_info ahxkey8_list[] = {
|
||||
|
||||
/* Amagami (PS2) [Enterbrain] */
|
||||
{"mituba",0},
|
||||
|
||||
/* StormLover!! (PSP), StormLover Kai!! (PSP) [Vridge] */
|
||||
{"HEXDPFMDKPQW",0},
|
||||
|
||||
/* Lucky Star: Net Idol Meister (PSP) [Vridge, Kadokawa Shoten] */
|
||||
/* Baka to Test to Shoukanjuu Portable (PSP) */
|
||||
{"JJOLIFJLE",0},
|
||||
|
||||
/* Ishin Renka: Ryouma Gaiden (PSP) [Vridge] */
|
||||
{"LQAFJOIEJ",0},
|
||||
|
||||
/* Lucky Star: Ryouou Gakuen Outousai Portable (PSP) [Vridge] */
|
||||
{"IUNOIRU",0},
|
||||
|
||||
/* Marriage Royale: Prism Story (PSP) [Vridge] */
|
||||
{"ROYMAR",0},
|
||||
|
||||
/* Nogizaka Haruka no Himitsu: Doujinshi Hajimemashita (PSP) [Vridge] */
|
||||
{"CLKMEOUHFLIE",0},
|
||||
|
||||
/* Nichijou: Uchuujin (PSP) [Vridge] */
|
||||
{"LJLOUHIU787",0},
|
||||
|
||||
/* StormLover Natsu Koi!! (PSP) [Vridge] */
|
||||
{"LIKDFJUIDJOQ",0},
|
||||
|
||||
/* Corpse Party: Book of Shadows (PSP) */
|
||||
{"\x83\x76\x83\x89\x83\x60\x83\x69Lovers_Day",0}, // "プラチナLovers_Day" in SHIFT-JIS
|
||||
|
||||
};
|
||||
|
||||
static const int ahxkey8_list_count = sizeof(ahxkey8_list) / sizeof(ahxkey8_list[0]);
|
||||
|
||||
#endif /* _AHX_KEYS_H_ */
|
@ -28,10 +28,10 @@ VGMSTREAM* init_vgmstream_bfstm(STREAMFILE* sf) {
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(sf,"bfstm"))
|
||||
goto fail;
|
||||
if (!is_id32be(0x00,sf, "FSTM"))
|
||||
goto fail;
|
||||
if (!check_extensions(sf,"bfstm"))
|
||||
goto fail;
|
||||
/* 0x06(2): header size (0x40)
|
||||
* 0x08: version (0x00000400)
|
||||
* 0x0c: file size */
|
||||
|
@ -54,7 +54,7 @@ VGMSTREAM* init_vgmstream_bnk_sony(STREAMFILE* sf) {
|
||||
data_offset = read_u32(0x10,sf);
|
||||
data_size = read_u32(0x14,sf);
|
||||
/* when sblk_offset >= 0x20: */
|
||||
/* 0x18: ZLSD small footer, rare [Yakuza 6's Puyo Puyo (PS4)] */
|
||||
/* 0x18: ZLSD small footer, rare in earlier versions [Yakuza 6's Puyo Puyo (PS4)] */
|
||||
/* 0x1c: ZLSD size */
|
||||
|
||||
/* SE banks, also used for music. Most table fields seems reserved/defaults and
|
||||
@ -66,14 +66,17 @@ VGMSTREAM* init_vgmstream_bnk_sony(STREAMFILE* sf) {
|
||||
if (read_u32(sblk_offset+0x00,sf) != get_id32be("klBS")) /* SBlk = SFX block */
|
||||
goto fail;
|
||||
sblk_version = read_u32(sblk_offset+0x04,sf);
|
||||
/* 0x08: flags? (sblk_version>=0x0d?, 0x03=Vita, 0x06=PS4)
|
||||
/* 0x08: flags? (sblk_version>=0x0d?, 0x03=Vita, 0x06=PS4, 0x05=PS5)
|
||||
* - 04: non-fixed bank?
|
||||
* - 100: has names
|
||||
* - 200: has user data
|
||||
*/
|
||||
/* 0x0c: block id */
|
||||
/* 0x10: block number */
|
||||
/* 0x11: padding */
|
||||
* - 200: has user data */
|
||||
/* version < v0x1a:
|
||||
* - 0x0c: block id
|
||||
* - 0x10: block number
|
||||
* - 0x11: padding
|
||||
* version >= v0x1a:
|
||||
* - 0x0c: hash (0x10)
|
||||
* - 0x1c: filename (0x100?) */
|
||||
//;VGM_LOG("BNK: sblk_offset=%lx, data_offset=%lx, sblk_version %x\n", sblk_offset, data_offset, sblk_version);
|
||||
|
||||
{
|
||||
@ -141,6 +144,8 @@ VGMSTREAM* init_vgmstream_bnk_sony(STREAMFILE* sf) {
|
||||
table2_suboffset = 0x00;
|
||||
break;
|
||||
|
||||
case 0x1a: /* Demon's Souls (PS5) */
|
||||
|
||||
default:
|
||||
vgm_logi("BNK: unknown version %x (report)\n", sblk_version);
|
||||
goto fail;
|
||||
|
203
src/meta/brstm.c
203
src/meta/brstm.c
@ -1,168 +1,123 @@
|
||||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
VGMSTREAM * init_vgmstream_brstm(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
VGMSTREAM* init_vgmstream_brstm(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
uint32_t start_offset, head_size, head_offset, info_offset;
|
||||
int channels, loop_flag, codec, version;
|
||||
|
||||
coding_t coding_type;
|
||||
|
||||
off_t head_offset;
|
||||
int codec_number;
|
||||
int channel_count;
|
||||
int loop_flag;
|
||||
/* Certain Super Paper Mario tracks have a 44.1KHz sample rate in the
|
||||
* header, but they should be played at 22.05KHz. We will make this
|
||||
* correction if we see a file with a .brstmspm extension. */
|
||||
int spm_flag = 0;
|
||||
/* Trauma Center Second Opinion has an odd, semi-corrupt header */
|
||||
int atlus_shrunken_head = 0;
|
||||
|
||||
off_t start_offset;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("brstm",filename_extension(filename))) {
|
||||
if (strcasecmp("brstmspm",filename_extension(filename))) goto fail;
|
||||
else spm_flag = 1;
|
||||
}
|
||||
|
||||
/* check header */
|
||||
if ((uint32_t)read_32bitBE(0,streamFile)!=0x5253544D) /* "RSTM" */
|
||||
/* checks */
|
||||
if (!is_id32be(0x00,sf, "RSTM"))
|
||||
goto fail;
|
||||
if ((uint32_t)read_32bitBE(4,streamFile)!=0xFEFF0100)
|
||||
{
|
||||
if ((uint32_t)read_32bitBE(4,streamFile)!=0xFEFF0001)
|
||||
goto fail;
|
||||
else
|
||||
atlus_shrunken_head = 1;
|
||||
|
||||
/* .brstm: standard
|
||||
* .brstmspm: fake hack */
|
||||
if (!check_extensions(sf,"brstm,brstmspm"))
|
||||
goto fail;
|
||||
|
||||
if (read_u16be(0x04, sf) != 0xFEFF) /* BE BOM for all Wii games */
|
||||
goto fail;
|
||||
|
||||
version = read_u16be(0x06, sf); /* 0.1 (Trauma Center), 1.0 (all others) */
|
||||
if (read_u32be(0x08, sf) != get_streamfile_size(sf))
|
||||
goto fail;
|
||||
|
||||
head_size = read_u16be(0x0c, sf);
|
||||
/* 0x0e: chunk count */
|
||||
|
||||
if (version == 0x0001) {
|
||||
/* smaller simpler header found in some (beta?) files */
|
||||
head_offset = head_size;
|
||||
info_offset = head_offset + 0x08;
|
||||
}
|
||||
else {
|
||||
/* chunk table: offset + sixe x N chunks */
|
||||
head_offset = read_u32be(0x10,sf); /* in practice same as head_size */
|
||||
info_offset = head_offset + 0x20;
|
||||
/* HEAD starts with a sub-chunk table (info, )*/
|
||||
}
|
||||
|
||||
/* get head offset, check */
|
||||
head_offset = read_32bitBE(0x10,streamFile);
|
||||
if (atlus_shrunken_head)
|
||||
{
|
||||
/* the HEAD chunk is where we would expect to find the offset of that
|
||||
* chunk... */
|
||||
if (!is_id32be(head_offset,sf, "HEAD"))
|
||||
goto fail;
|
||||
/* 0x04: chunk size (set to 0x8 in v0.1) */
|
||||
|
||||
if ((uint32_t)head_offset!=0x48454144 || read_32bitBE(0x14,streamFile) != 8)
|
||||
goto fail;
|
||||
codec = read_u8(info_offset+0x00,sf);
|
||||
loop_flag = read_u8(info_offset+0x01,sf);
|
||||
channels = read_u8(info_offset+0x02,sf);
|
||||
|
||||
head_offset = -8; /* most of the normal Nintendo RSTM offsets work
|
||||
with this assumption */
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((uint32_t)read_32bitBE(head_offset,streamFile)!=0x48454144) /* "HEAD" */
|
||||
goto fail;
|
||||
}
|
||||
start_offset = read_u32be(info_offset+0x10,sf); /* inside DATA chunk */
|
||||
|
||||
/* check type details */
|
||||
codec_number = read_8bit(head_offset+0x20,streamFile);
|
||||
loop_flag = read_8bit(head_offset+0x21,streamFile);
|
||||
channel_count = read_8bit(head_offset+0x22,streamFile);
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channels, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
switch (codec_number) {
|
||||
vgmstream->meta_type = meta_RSTM;
|
||||
|
||||
vgmstream->sample_rate = read_u16be(info_offset+0x04,sf);
|
||||
vgmstream->loop_start_sample = read_s32be(info_offset+0x08,sf);
|
||||
vgmstream->num_samples = read_s32be(info_offset+0x0c,sf);
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
|
||||
vgmstream->interleave_block_size = read_u32be(info_offset+0x18,sf);
|
||||
vgmstream->interleave_last_block_size = read_u32be(info_offset+0x28,sf);
|
||||
|
||||
/* many Super Paper Mario tracks have a 44.1KHz sample rate in the header,
|
||||
* but they should be played at 22.05KHz; detect with fake extension */
|
||||
if (vgmstream->sample_rate == 44100 && check_extensions(sf, "brstmspm")) //TODO remove
|
||||
vgmstream->sample_rate = 22050;
|
||||
|
||||
vgmstream->layout_type = (channels == 1) ? layout_none : layout_interleave;
|
||||
switch(codec) {
|
||||
case 0:
|
||||
coding_type = coding_PCM8;
|
||||
vgmstream->coding_type = coding_PCM8;
|
||||
break;
|
||||
case 1:
|
||||
coding_type = coding_PCM16BE;
|
||||
vgmstream->coding_type = coding_PCM16BE;
|
||||
break;
|
||||
case 2:
|
||||
coding_type = coding_NGC_DSP;
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (channel_count < 1) goto fail;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
vgmstream->num_samples = read_32bitBE(head_offset+0x2c,streamFile);
|
||||
vgmstream->sample_rate = (uint16_t)read_16bitBE(head_offset+0x24,streamFile);
|
||||
/* channels and loop flag are set by allocate_vgmstream */
|
||||
vgmstream->loop_start_sample = read_32bitBE(head_offset+0x28,streamFile);
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
|
||||
vgmstream->coding_type = coding_type;
|
||||
vgmstream->layout_type = (channel_count == 1) ? layout_none : layout_interleave;
|
||||
vgmstream->meta_type = meta_RSTM;
|
||||
if (atlus_shrunken_head)
|
||||
vgmstream->meta_type = meta_RSTM_shrunken;
|
||||
|
||||
if (spm_flag&& vgmstream->sample_rate == 44100) {
|
||||
vgmstream->meta_type = meta_RSTM_SPM;
|
||||
vgmstream->sample_rate = 22050;
|
||||
}
|
||||
|
||||
vgmstream->interleave_block_size = read_32bitBE(head_offset+0x38,streamFile);
|
||||
vgmstream->interleave_last_block_size = read_32bitBE(head_offset+0x48,streamFile);
|
||||
|
||||
// TODO read hist
|
||||
if (vgmstream->coding_type == coding_NGC_DSP) {
|
||||
off_t coef_offset;
|
||||
off_t head_part3_offset;
|
||||
off_t adpcm_header_offset;
|
||||
int i,j;
|
||||
int coef_spacing;
|
||||
int i, ch;
|
||||
|
||||
if (atlus_shrunken_head)
|
||||
{
|
||||
coef_offset = 0x50;
|
||||
coef_spacing = 0x30;
|
||||
|
||||
for (j = 0; j < vgmstream->channels; j++) {
|
||||
for (i = 0; i < 16; i++) {
|
||||
vgmstream->ch[j].adpcm_coef[i] = read_16bitBE(head_offset + coef_offset + j * coef_spacing + i * 2,streamFile);
|
||||
}
|
||||
}
|
||||
if (version == 0x0001) {
|
||||
/* standard */
|
||||
VGM_LOG("ss=%x\n", head_offset + 0x38);
|
||||
dsp_read_coefs_be(vgmstream, sf, head_offset + 0x38, 0x30);
|
||||
}
|
||||
else
|
||||
{
|
||||
head_part3_offset = read_32bitBE(head_offset + 0x1c, streamFile);
|
||||
else {
|
||||
uint32_t head_part3_offset = read_32bitBE(head_offset + 0x1c, sf);
|
||||
|
||||
for (j = 0; j < vgmstream->channels; j++) {
|
||||
/* read from offset table */
|
||||
for (ch = 0; ch < vgmstream->channels; ch++) {
|
||||
adpcm_header_offset = head_offset + 0x08
|
||||
+ head_part3_offset + 0x04 /* skip over HEAD part 3 */
|
||||
+ j * 0x08 /* skip to channel's ADPCM offset table */
|
||||
+ ch * 0x08 /* skip to channel's ADPCM offset table */
|
||||
+ 0x04; /* ADPCM header offset field */
|
||||
|
||||
coef_offset = head_offset + 0x08
|
||||
+ read_32bitBE(adpcm_header_offset, streamFile)
|
||||
+ read_u32be(adpcm_header_offset, sf)
|
||||
+ 0x08; /* coeffs field */
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
vgmstream->ch[j].adpcm_coef[i] = read_16bitBE(coef_offset + i * 2, streamFile);
|
||||
vgmstream->ch[ch].adpcm_coef[i] = read_s16be(coef_offset + i * 2, sf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
start_offset = read_32bitBE(head_offset+0x30,streamFile);
|
||||
|
||||
/* open the file for reading by each channel */
|
||||
{
|
||||
int i;
|
||||
for (i=0;i<channel_count;i++) {
|
||||
vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
|
||||
if (!vgmstream->ch[i].streamfile) goto fail;
|
||||
|
||||
vgmstream->ch[i].channel_start_offset=
|
||||
vgmstream->ch[i].offset=
|
||||
start_offset + i*vgmstream->interleave_block_size;
|
||||
}
|
||||
}
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -95,7 +95,7 @@ typedef struct {
|
||||
int is_at9;
|
||||
} riff_fmt_chunk;
|
||||
|
||||
static int read_fmt(int big_endian, STREAMFILE* sf, off_t offset, riff_fmt_chunk* fmt, int mwv) {
|
||||
static int read_fmt(int big_endian, STREAMFILE* sf, off_t offset, riff_fmt_chunk* fmt) {
|
||||
uint32_t (*read_u32)(off_t,STREAMFILE*) = big_endian ? read_u32be : read_u32le;
|
||||
uint16_t (*read_u16)(off_t,STREAMFILE*) = big_endian ? read_u16be : read_u16le;
|
||||
|
||||
@ -227,7 +227,6 @@ static int read_fmt(int big_endian, STREAMFILE* sf, off_t offset, riff_fmt_chunk
|
||||
break;
|
||||
|
||||
case 0x0555: /* Level-5 0x555 ADPCM (unofficial) */
|
||||
if (!mwv) goto fail;
|
||||
fmt->coding_type = coding_L5_555;
|
||||
fmt->interleave = 0x12;
|
||||
break;
|
||||
@ -337,9 +336,8 @@ VGMSTREAM* init_vgmstream_riff(STREAMFILE* sf) {
|
||||
|
||||
int FormatChunkFound = 0, DataChunkFound = 0, JunkFound = 0;
|
||||
|
||||
int mwv = 0;
|
||||
off_t mwv_pflt_offset = -1;
|
||||
off_t mwv_ctrl_offset = -1;
|
||||
off_t mwv_pflt_offset = 0;
|
||||
off_t mwv_ctrl_offset = 0;
|
||||
int ignore_riff_size = 0;
|
||||
|
||||
|
||||
@ -347,6 +345,13 @@ VGMSTREAM* init_vgmstream_riff(STREAMFILE* sf) {
|
||||
if (!is_id32be(0x00,sf,"RIFF"))
|
||||
goto fail;
|
||||
|
||||
riff_size = read_u32le(0x04,sf);
|
||||
|
||||
if (!is_id32be(0x08,sf, "WAVE"))
|
||||
goto fail;
|
||||
|
||||
file_size = get_streamfile_size(sf);
|
||||
|
||||
/* .lwav: to avoid hijacking .wav
|
||||
* .xwav: fake for Xbox games (not needed anymore)
|
||||
* .da: The Great Battle VI (PS1)
|
||||
@ -379,24 +384,12 @@ VGMSTREAM* init_vgmstream_riff(STREAMFILE* sf) {
|
||||
* .ogg/logg: Luftrausers (Vita)[ATRAC9]
|
||||
* .p1d: Farming Simulator 15 (Vita)[ATRAC9]
|
||||
* .xms: Ty the Tasmanian Tiger (Xbox)
|
||||
* .mus: Burnout Legends/Dominator (PSP)
|
||||
*/
|
||||
if ( check_extensions(sf, "wav,lwav,xwav,da,dax,cd,med,snd,adx,adp,xss,xsew,adpcm,adw,wd,,sbv,wvx,str,at3,rws,aud,at9,ckd,saf,ima,nsa,pcm,xvag,ogg,logg,p1d,xms") ) {
|
||||
;
|
||||
}
|
||||
else if ( check_extensions(sf, "mwv") ) {
|
||||
mwv = 1;
|
||||
}
|
||||
else {
|
||||
if (!check_extensions(sf, "wav,lwav,xwav,mwv,da,dax,cd,med,snd,adx,adp,xss,xsew,adpcm,adw,wd,,sbv,wvx,str,at3,rws,aud,at9,ckd,saf,ima,nsa,pcm,xvag,ogg,logg,p1d,xms,mus")) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
riff_size = read_u32le(0x04,sf);
|
||||
|
||||
if (!is_id32be(0x08,sf, "WAVE"))
|
||||
goto fail;
|
||||
|
||||
file_size = get_streamfile_size(sf);
|
||||
|
||||
/* some games have wonky sizes, selectively fix to catch bad rips and new mutations */
|
||||
if (file_size != riff_size + 0x08) {
|
||||
uint16_t codec = read_u16le(0x14,sf);
|
||||
@ -425,7 +418,7 @@ VGMSTREAM* init_vgmstream_riff(STREAMFILE* sf) {
|
||||
else if (codec == 0xFFFE && riff_size + 0x08 + 0x18 == file_size)
|
||||
riff_size += 0x18; /* [F1 2011 (Vita)] (adds a "pada" chunk but RIFF size wasn't updated) */
|
||||
|
||||
else if (mwv) {
|
||||
else if (codec == 0x0555) {
|
||||
int channels = read_u16le(0x16, sf); /* [Dragon Quest VIII (PS2), Rogue Galaxy (PS2)] */
|
||||
size_t file_size_fixed = riff_size + 0x08 + 0x04 * (channels - 1);
|
||||
|
||||
@ -486,7 +479,7 @@ VGMSTREAM* init_vgmstream_riff(STREAMFILE* sf) {
|
||||
if (FormatChunkFound) goto fail; /* only one per file */
|
||||
FormatChunkFound = 1;
|
||||
|
||||
if (!read_fmt(0, sf, current_chunk, &fmt, mwv))
|
||||
if (!read_fmt(0, sf, current_chunk, &fmt))
|
||||
goto fail;
|
||||
|
||||
/* some Dreamcast/Naomi games again [Headhunter (DC), Bomber hehhe (DC), Rayman 2 (DC)] */
|
||||
@ -574,12 +567,10 @@ VGMSTREAM* init_vgmstream_riff(STREAMFILE* sf) {
|
||||
goto fail; /* parsed elsewhere */
|
||||
|
||||
case 0x70666c74: /* "pflt" (.mwv extension) */
|
||||
if (!mwv) break; /* ignore if not in an mwv */
|
||||
mwv_pflt_offset = current_chunk; /* predictor filters */
|
||||
break;
|
||||
|
||||
case 0x6374726c: /* "ctrl" (.mwv extension) */
|
||||
if (!mwv) break;
|
||||
loop_flag = read_32bitLE(current_chunk+0x08, sf);
|
||||
mwv_ctrl_offset = current_chunk;
|
||||
break;
|
||||
@ -725,7 +716,6 @@ VGMSTREAM* init_vgmstream_riff(STREAMFILE* sf) {
|
||||
break;
|
||||
|
||||
case coding_L5_555:
|
||||
if (!mwv) goto fail;
|
||||
vgmstream->num_samples = data_size / 0x12 / fmt.channels * 32;
|
||||
|
||||
/* coefs */
|
||||
@ -735,7 +725,7 @@ VGMSTREAM* init_vgmstream_riff(STREAMFILE* sf) {
|
||||
int filter_count = read_32bitLE(mwv_pflt_offset+0x0c, sf);
|
||||
if (filter_count > 0x20) goto fail;
|
||||
|
||||
if (mwv_pflt_offset == -1 ||
|
||||
if (!mwv_pflt_offset ||
|
||||
read_32bitLE(mwv_pflt_offset+0x08, sf) != filter_order ||
|
||||
read_32bitLE(mwv_pflt_offset+0x04, sf) < 8 + filter_count * 4 * filter_order)
|
||||
goto fail;
|
||||
@ -908,9 +898,10 @@ VGMSTREAM* init_vgmstream_riff(STREAMFILE* sf) {
|
||||
vgmstream->loop_end_sample = loop_end_wsmp;
|
||||
vgmstream->meta_type = meta_RIFF_WAVE_wsmp;
|
||||
}
|
||||
else if (mwv && mwv_ctrl_offset != -1) {
|
||||
vgmstream->loop_start_sample = read_32bitLE(mwv_ctrl_offset+12, sf);
|
||||
else if (fmt.coding_type == coding_L5_555 && mwv_ctrl_offset) {
|
||||
vgmstream->loop_start_sample = read_s32le(mwv_ctrl_offset + 0x0c, sf);
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
vgmstream->meta_type = meta_RIFF_WAVE_MWV;
|
||||
}
|
||||
else if (loop_start_cue != -1) {
|
||||
vgmstream->loop_start_sample = loop_start_cue;
|
||||
@ -927,9 +918,6 @@ VGMSTREAM* init_vgmstream_riff(STREAMFILE* sf) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mwv) {
|
||||
vgmstream->meta_type = meta_RIFF_WAVE_MWV;
|
||||
}
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
|
||||
goto fail;
|
||||
@ -1105,7 +1093,7 @@ VGMSTREAM* init_vgmstream_rifx(STREAMFILE* sf) {
|
||||
if (FormatChunkFound) goto fail;
|
||||
FormatChunkFound = 1;
|
||||
|
||||
if (!read_fmt(1, sf, current_chunk, &fmt, 0))
|
||||
if (!read_fmt(1, sf, current_chunk, &fmt))
|
||||
goto fail;
|
||||
|
||||
break;
|
||||
|
@ -106,6 +106,12 @@ VGMSTREAM* init_vgmstream_rwsd(STREAMFILE* sf) {
|
||||
|
||||
stream_size = read_32bitBE(wave_offset + 0x50,sf);
|
||||
|
||||
/* this meta is a hack as WSD is just note info, and data offsets are elsewhere in the brsar,
|
||||
* while this assumes whatever data follows RWSD must belong to it (common but fails in Wii Sports),
|
||||
* detect data excess and reject (probably should use brawlbox's info offsets) */
|
||||
if (stream_size * channels + 0x10000 < get_streamfile_size(sf) - start_offset)
|
||||
goto fail;
|
||||
|
||||
/* open the file for reading by each channel */
|
||||
{
|
||||
int i;
|
||||
|
@ -1,29 +1,70 @@
|
||||
#ifndef _MPEG_BITREADER_H
|
||||
#define _MPEG_BITREADER_H
|
||||
#ifndef _BITSTREAM_MSB_H
|
||||
#define _BITSTREAM_MSB_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* Simple bitreader for MPEG/standard bit format.
|
||||
* Kept in .h since it's slightly faster (compiler can optimize statics better) */
|
||||
|
||||
* Kept in .h since it's slightly faster (compiler can optimize better) */
|
||||
|
||||
typedef struct {
|
||||
uint8_t* buf; /* buffer to read/write */
|
||||
size_t bufsize; /* max size of the buffer */
|
||||
uint32_t b_off; /* current offset in bits inside the buffer */
|
||||
size_t bufsize; /* max size */
|
||||
size_t b_max; /* max size in bits */
|
||||
uint32_t b_off; /* current offset in bits inside buffer */
|
||||
} bitstream_t;
|
||||
|
||||
/* convenience util */
|
||||
static void init_bitstream(bitstream_t* b, uint8_t* buf, size_t bufsize) {
|
||||
b->buf = buf;
|
||||
b->bufsize = bufsize;
|
||||
b->b_off = 0;
|
||||
|
||||
static inline void bm_setup(bitstream_t* bs, uint8_t* buf, size_t bufsize) {
|
||||
bs->buf = buf;
|
||||
bs->bufsize = bufsize;
|
||||
bs->b_max = bufsize * 8;
|
||||
bs->b_off = 0;
|
||||
}
|
||||
|
||||
/* Read bits (max 32) from buf and update the bit offset. Order is BE (MSF). */
|
||||
static int rb_bits(bitstream_t* ib, uint32_t bits, uint32_t* value) {
|
||||
static inline int bm_set(bitstream_t* bs, uint32_t b_off) {
|
||||
if (bs->b_off > bs->b_max)
|
||||
goto fail;
|
||||
|
||||
bs->b_off = b_off;
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int bm_fill(bitstream_t* bs, uint32_t bytes) {
|
||||
if (bs->b_off > bs->b_max)
|
||||
goto fail;
|
||||
|
||||
bs->bufsize += bytes;
|
||||
bs->b_max += bytes * 8;
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int bm_skip(bitstream_t* bs, uint32_t bits) {
|
||||
if (bs->b_off + bits > bs->b_max)
|
||||
goto fail;
|
||||
|
||||
bs->b_off += bits;
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int bm_pos(bitstream_t* bs) {
|
||||
return bs->b_off;
|
||||
}
|
||||
|
||||
/* Read bits (max 32) from buf and update the bit offset. Order is BE (MSB). */
|
||||
static inline int bm_get(bitstream_t* ib, uint32_t bits, uint32_t* value) {
|
||||
uint32_t shift, pos, val;
|
||||
int i, bit_buf, bit_val;
|
||||
|
||||
if (bits > 32 || ib->b_off + bits > ib->bufsize * 8)
|
||||
if (bits > 32 || ib->b_off + bits > ib->b_max)
|
||||
goto fail;
|
||||
|
||||
pos = ib->b_off / 8; /* byte offset */
|
||||
@ -48,18 +89,17 @@ static int rb_bits(bitstream_t* ib, uint32_t bits, uint32_t* value) {
|
||||
ib->b_off += bits;
|
||||
return 1;
|
||||
fail:
|
||||
VGM_LOG("BITREADER: read fail\n");
|
||||
//VGM_LOG("BITREADER: read fail\n");
|
||||
*value = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef BITSTREAM_READ_ONLY
|
||||
/* Write bits (max 32) to buf and update the bit offset. Order is BE (MSF). */
|
||||
static int wb_bits(bitstream_t* ob, uint32_t bits, uint32_t value) {
|
||||
/* Write bits (max 32) to buf and update the bit offset. Order is BE (MSB). */
|
||||
static inline int bm_put(bitstream_t* ob, uint32_t bits, uint32_t value) {
|
||||
uint32_t shift, pos;
|
||||
int i, bit_val, bit_buf;
|
||||
|
||||
if (bits > 32 || ob->b_off + bits > ob->bufsize * 8)
|
||||
if (bits > 32 || ob->b_off + bits > ob->b_max)
|
||||
goto fail;
|
||||
|
||||
pos = ob->b_off / 8; /* byte offset */
|
||||
@ -86,6 +126,5 @@ static int wb_bits(bitstream_t* ob, uint32_t bits, uint32_t value) {
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
139
src/util/cri_keys.c
Normal file
139
src/util/cri_keys.c
Normal file
@ -0,0 +1,139 @@
|
||||
#include "cri_keys.h"
|
||||
#include <string.h>
|
||||
|
||||
|
||||
/* preloaded list used to derive keystrings from ADX_Decoder, found in executables (see VGAudio for how to calculate) */
|
||||
static const uint16_t key8_primes[0x400] = {
|
||||
0x401B,0x4021,0x4025,0x402B,0x4031,0x403F,0x4043,0x4045,0x405D,0x4061,0x4067,0x406D,0x4087,0x4091,0x40A3,0x40A9,
|
||||
0x40B1,0x40B7,0x40BD,0x40DB,0x40DF,0x40EB,0x40F7,0x40F9,0x4109,0x410B,0x4111,0x4115,0x4121,0x4133,0x4135,0x413B,
|
||||
0x413F,0x4159,0x4165,0x416B,0x4177,0x417B,0x4193,0x41AB,0x41B7,0x41BD,0x41BF,0x41CB,0x41E7,0x41EF,0x41F3,0x41F9,
|
||||
0x4205,0x4207,0x4219,0x421F,0x4223,0x4229,0x422F,0x4243,0x4253,0x4255,0x425B,0x4261,0x4273,0x427D,0x4283,0x4285,
|
||||
0x4289,0x4291,0x4297,0x429D,0x42B5,0x42C5,0x42CB,0x42D3,0x42DD,0x42E3,0x42F1,0x4307,0x430F,0x431F,0x4325,0x4327,
|
||||
0x4333,0x4337,0x4339,0x434F,0x4357,0x4369,0x438B,0x438D,0x4393,0x43A5,0x43A9,0x43AF,0x43B5,0x43BD,0x43C7,0x43CF,
|
||||
0x43E1,0x43E7,0x43EB,0x43ED,0x43F1,0x43F9,0x4409,0x440B,0x4417,0x4423,0x4429,0x443B,0x443F,0x4445,0x444B,0x4451,
|
||||
0x4453,0x4459,0x4465,0x446F,0x4483,0x448F,0x44A1,0x44A5,0x44AB,0x44AD,0x44BD,0x44BF,0x44C9,0x44D7,0x44DB,0x44F9,
|
||||
0x44FB,0x4505,0x4511,0x4513,0x452B,0x4531,0x4541,0x4549,0x4553,0x4555,0x4561,0x4577,0x457D,0x457F,0x458F,0x45A3,
|
||||
0x45AD,0x45AF,0x45BB,0x45C7,0x45D9,0x45E3,0x45EF,0x45F5,0x45F7,0x4601,0x4603,0x4609,0x4613,0x4625,0x4627,0x4633,
|
||||
0x4639,0x463D,0x4643,0x4645,0x465D,0x4679,0x467B,0x467F,0x4681,0x468B,0x468D,0x469D,0x46A9,0x46B1,0x46C7,0x46C9,
|
||||
0x46CF,0x46D3,0x46D5,0x46DF,0x46E5,0x46F9,0x4705,0x470F,0x4717,0x4723,0x4729,0x472F,0x4735,0x4739,0x474B,0x474D,
|
||||
0x4751,0x475D,0x476F,0x4771,0x477D,0x4783,0x4787,0x4789,0x4799,0x47A5,0x47B1,0x47BF,0x47C3,0x47CB,0x47DD,0x47E1,
|
||||
0x47ED,0x47FB,0x4801,0x4807,0x480B,0x4813,0x4819,0x481D,0x4831,0x483D,0x4847,0x4855,0x4859,0x485B,0x486B,0x486D,
|
||||
0x4879,0x4897,0x489B,0x48A1,0x48B9,0x48CD,0x48E5,0x48EF,0x48F7,0x4903,0x490D,0x4919,0x491F,0x492B,0x4937,0x493D,
|
||||
0x4945,0x4955,0x4963,0x4969,0x496D,0x4973,0x4997,0x49AB,0x49B5,0x49D3,0x49DF,0x49E1,0x49E5,0x49E7,0x4A03,0x4A0F,
|
||||
0x4A1D,0x4A23,0x4A39,0x4A41,0x4A45,0x4A57,0x4A5D,0x4A6B,0x4A7D,0x4A81,0x4A87,0x4A89,0x4A8F,0x4AB1,0x4AC3,0x4AC5,
|
||||
0x4AD5,0x4ADB,0x4AED,0x4AEF,0x4B07,0x4B0B,0x4B0D,0x4B13,0x4B1F,0x4B25,0x4B31,0x4B3B,0x4B43,0x4B49,0x4B59,0x4B65,
|
||||
0x4B6D,0x4B77,0x4B85,0x4BAD,0x4BB3,0x4BB5,0x4BBB,0x4BBF,0x4BCB,0x4BD9,0x4BDD,0x4BDF,0x4BE3,0x4BE5,0x4BE9,0x4BF1,
|
||||
0x4BF7,0x4C01,0x4C07,0x4C0D,0x4C0F,0x4C15,0x4C1B,0x4C21,0x4C2D,0x4C33,0x4C4B,0x4C55,0x4C57,0x4C61,0x4C67,0x4C73,
|
||||
0x4C79,0x4C7F,0x4C8D,0x4C93,0x4C99,0x4CCD,0x4CE1,0x4CE7,0x4CF1,0x4CF3,0x4CFD,0x4D05,0x4D0F,0x4D1B,0x4D27,0x4D29,
|
||||
0x4D2F,0x4D33,0x4D41,0x4D51,0x4D59,0x4D65,0x4D6B,0x4D81,0x4D83,0x4D8D,0x4D95,0x4D9B,0x4DB1,0x4DB3,0x4DC9,0x4DCF,
|
||||
0x4DD7,0x4DE1,0x4DED,0x4DF9,0x4DFB,0x4E05,0x4E0B,0x4E17,0x4E19,0x4E1D,0x4E2B,0x4E35,0x4E37,0x4E3D,0x4E4F,0x4E53,
|
||||
0x4E5F,0x4E67,0x4E79,0x4E85,0x4E8B,0x4E91,0x4E95,0x4E9B,0x4EA1,0x4EAF,0x4EB3,0x4EB5,0x4EC1,0x4ECD,0x4ED1,0x4ED7,
|
||||
0x4EE9,0x4EFB,0x4F07,0x4F09,0x4F19,0x4F25,0x4F2D,0x4F3F,0x4F49,0x4F63,0x4F67,0x4F6D,0x4F75,0x4F7B,0x4F81,0x4F85,
|
||||
0x4F87,0x4F91,0x4FA5,0x4FA9,0x4FAF,0x4FB7,0x4FBB,0x4FCF,0x4FD9,0x4FDB,0x4FFD,0x4FFF,0x5003,0x501B,0x501D,0x5029,
|
||||
0x5035,0x503F,0x5045,0x5047,0x5053,0x5071,0x5077,0x5083,0x5093,0x509F,0x50A1,0x50B7,0x50C9,0x50D5,0x50E3,0x50ED,
|
||||
0x50EF,0x50FB,0x5107,0x510B,0x510D,0x5111,0x5117,0x5123,0x5125,0x5135,0x5147,0x5149,0x5171,0x5179,0x5189,0x518F,
|
||||
0x5197,0x51A1,0x51A3,0x51A7,0x51B9,0x51C1,0x51CB,0x51D3,0x51DF,0x51E3,0x51F5,0x51F7,0x5209,0x5213,0x5215,0x5219,
|
||||
0x521B,0x521F,0x5227,0x5243,0x5245,0x524B,0x5261,0x526D,0x5273,0x5281,0x5293,0x5297,0x529D,0x52A5,0x52AB,0x52B1,
|
||||
0x52BB,0x52C3,0x52C7,0x52C9,0x52DB,0x52E5,0x52EB,0x52FF,0x5315,0x531D,0x5323,0x5341,0x5345,0x5347,0x534B,0x535D,
|
||||
0x5363,0x5381,0x5383,0x5387,0x538F,0x5395,0x5399,0x539F,0x53AB,0x53B9,0x53DB,0x53E9,0x53EF,0x53F3,0x53F5,0x53FB,
|
||||
0x53FF,0x540D,0x5411,0x5413,0x5419,0x5435,0x5437,0x543B,0x5441,0x5449,0x5453,0x5455,0x545F,0x5461,0x546B,0x546D,
|
||||
0x5471,0x548F,0x5491,0x549D,0x54A9,0x54B3,0x54C5,0x54D1,0x54DF,0x54E9,0x54EB,0x54F7,0x54FD,0x5507,0x550D,0x551B,
|
||||
0x5527,0x552B,0x5539,0x553D,0x554F,0x5551,0x555B,0x5563,0x5567,0x556F,0x5579,0x5585,0x5597,0x55A9,0x55B1,0x55B7,
|
||||
0x55C9,0x55D9,0x55E7,0x55ED,0x55F3,0x55FD,0x560B,0x560F,0x5615,0x5617,0x5623,0x562F,0x5633,0x5639,0x563F,0x564B,
|
||||
0x564D,0x565D,0x565F,0x566B,0x5671,0x5675,0x5683,0x5689,0x568D,0x568F,0x569B,0x56AD,0x56B1,0x56D5,0x56E7,0x56F3,
|
||||
0x56FF,0x5701,0x5705,0x5707,0x570B,0x5713,0x571F,0x5723,0x5747,0x574D,0x575F,0x5761,0x576D,0x5777,0x577D,0x5789,
|
||||
0x57A1,0x57A9,0x57AF,0x57B5,0x57C5,0x57D1,0x57D3,0x57E5,0x57EF,0x5803,0x580D,0x580F,0x5815,0x5827,0x582B,0x582D,
|
||||
0x5855,0x585B,0x585D,0x586D,0x586F,0x5873,0x587B,0x588D,0x5897,0x58A3,0x58A9,0x58AB,0x58B5,0x58BD,0x58C1,0x58C7,
|
||||
0x58D3,0x58D5,0x58DF,0x58F1,0x58F9,0x58FF,0x5903,0x5917,0x591B,0x5921,0x5945,0x594B,0x594D,0x5957,0x595D,0x5975,
|
||||
0x597B,0x5989,0x5999,0x599F,0x59B1,0x59B3,0x59BD,0x59D1,0x59DB,0x59E3,0x59E9,0x59ED,0x59F3,0x59F5,0x59FF,0x5A01,
|
||||
0x5A0D,0x5A11,0x5A13,0x5A17,0x5A1F,0x5A29,0x5A2F,0x5A3B,0x5A4D,0x5A5B,0x5A67,0x5A77,0x5A7F,0x5A85,0x5A95,0x5A9D,
|
||||
0x5AA1,0x5AA3,0x5AA9,0x5ABB,0x5AD3,0x5AE5,0x5AEF,0x5AFB,0x5AFD,0x5B01,0x5B0F,0x5B19,0x5B1F,0x5B25,0x5B2B,0x5B3D,
|
||||
0x5B49,0x5B4B,0x5B67,0x5B79,0x5B87,0x5B97,0x5BA3,0x5BB1,0x5BC9,0x5BD5,0x5BEB,0x5BF1,0x5BF3,0x5BFD,0x5C05,0x5C09,
|
||||
0x5C0B,0x5C0F,0x5C1D,0x5C29,0x5C2F,0x5C33,0x5C39,0x5C47,0x5C4B,0x5C4D,0x5C51,0x5C6F,0x5C75,0x5C77,0x5C7D,0x5C87,
|
||||
0x5C89,0x5CA7,0x5CBD,0x5CBF,0x5CC3,0x5CC9,0x5CD1,0x5CD7,0x5CDD,0x5CED,0x5CF9,0x5D05,0x5D0B,0x5D13,0x5D17,0x5D19,
|
||||
0x5D31,0x5D3D,0x5D41,0x5D47,0x5D4F,0x5D55,0x5D5B,0x5D65,0x5D67,0x5D6D,0x5D79,0x5D95,0x5DA3,0x5DA9,0x5DAD,0x5DB9,
|
||||
0x5DC1,0x5DC7,0x5DD3,0x5DD7,0x5DDD,0x5DEB,0x5DF1,0x5DFD,0x5E07,0x5E0D,0x5E13,0x5E1B,0x5E21,0x5E27,0x5E2B,0x5E2D,
|
||||
0x5E31,0x5E39,0x5E45,0x5E49,0x5E57,0x5E69,0x5E73,0x5E75,0x5E85,0x5E8B,0x5E9F,0x5EA5,0x5EAF,0x5EB7,0x5EBB,0x5ED9,
|
||||
0x5EFD,0x5F09,0x5F11,0x5F27,0x5F33,0x5F35,0x5F3B,0x5F47,0x5F57,0x5F5D,0x5F63,0x5F65,0x5F77,0x5F7B,0x5F95,0x5F99,
|
||||
0x5FA1,0x5FB3,0x5FBD,0x5FC5,0x5FCF,0x5FD5,0x5FE3,0x5FE7,0x5FFB,0x6011,0x6023,0x602F,0x6037,0x6053,0x605F,0x6065,
|
||||
0x606B,0x6073,0x6079,0x6085,0x609D,0x60AD,0x60BB,0x60BF,0x60CD,0x60D9,0x60DF,0x60E9,0x60F5,0x6109,0x610F,0x6113,
|
||||
0x611B,0x612D,0x6139,0x614B,0x6155,0x6157,0x615B,0x616F,0x6179,0x6187,0x618B,0x6191,0x6193,0x619D,0x61B5,0x61C7,
|
||||
0x61C9,0x61CD,0x61E1,0x61F1,0x61FF,0x6209,0x6217,0x621D,0x6221,0x6227,0x623B,0x6241,0x624B,0x6251,0x6253,0x625F,
|
||||
0x6265,0x6283,0x628D,0x6295,0x629B,0x629F,0x62A5,0x62AD,0x62D5,0x62D7,0x62DB,0x62DD,0x62E9,0x62FB,0x62FF,0x6305,
|
||||
0x630D,0x6317,0x631D,0x632F,0x6341,0x6343,0x634F,0x635F,0x6367,0x636D,0x6371,0x6377,0x637D,0x637F,0x63B3,0x63C1,
|
||||
0x63C5,0x63D9,0x63E9,0x63EB,0x63EF,0x63F5,0x6401,0x6403,0x6409,0x6415,0x6421,0x6427,0x642B,0x6439,0x6443,0x6449,
|
||||
0x644F,0x645D,0x6467,0x6475,0x6485,0x648D,0x6493,0x649F,0x64A3,0x64AB,0x64C1,0x64C7,0x64C9,0x64DB,0x64F1,0x64F7,
|
||||
0x64F9,0x650B,0x6511,0x6521,0x652F,0x6539,0x653F,0x654B,0x654D,0x6553,0x6557,0x655F,0x6571,0x657D,0x658D,0x658F,
|
||||
0x6593,0x65A1,0x65A5,0x65AD,0x65B9,0x65C5,0x65E3,0x65F3,0x65FB,0x65FF,0x6601,0x6607,0x661D,0x6629,0x6631,0x663B,
|
||||
0x6641,0x6647,0x664D,0x665B,0x6661,0x6673,0x667D,0x6689,0x668B,0x6695,0x6697,0x669B,0x66B5,0x66B9,0x66C5,0x66CD,
|
||||
0x66D1,0x66E3,0x66EB,0x66F5,0x6703,0x6713,0x6719,0x671F,0x6727,0x6731,0x6737,0x673F,0x6745,0x6751,0x675B,0x676F,
|
||||
0x6779,0x6781,0x6785,0x6791,0x67AB,0x67BD,0x67C1,0x67CD,0x67DF,0x67E5,0x6803,0x6809,0x6811,0x6817,0x682D,0x6839,
|
||||
};
|
||||
|
||||
void cri_key8_derive(const char* key8, uint16_t* p_key1, uint16_t* p_key2, uint16_t* p_key3) {
|
||||
size_t key_size;
|
||||
uint16_t key1 = 0, key2 = 0, key3 = 0;
|
||||
int i;
|
||||
|
||||
if (key8 == NULL || key8[0] == '\0') /* strlen >= 1 */
|
||||
goto end;
|
||||
|
||||
/* calcs as found in exes, though there is some unrolling in the original code */
|
||||
key_size = strlen(key8);
|
||||
key1 = key8_primes[0x100];
|
||||
key2 = key8_primes[0x200];
|
||||
key3 = key8_primes[0x300];
|
||||
|
||||
for (i = 0; i < key_size; i++) {
|
||||
char c = key8[i];
|
||||
key1 = key8_primes[key1 * key8_primes[c + 0x80] % 0x400];
|
||||
key2 = key8_primes[key2 * key8_primes[c + 0x80] % 0x400];
|
||||
key3 = key8_primes[key3 * key8_primes[c + 0x80] % 0x400];
|
||||
}
|
||||
|
||||
end:
|
||||
*p_key1 = key1;
|
||||
*p_key2 = key2;
|
||||
*p_key3 = key3;
|
||||
}
|
||||
|
||||
|
||||
void cri_key9_derive(uint64_t key9, uint16_t subkey, uint16_t* p_key1, uint16_t* p_key2, uint16_t* p_key3) {
|
||||
uint16_t key1 = 0, key2 = 0, key3 = 0;
|
||||
|
||||
/* 0 is ignored by CRI's encoder, only from 1..18446744073709551615 */
|
||||
if (key9 == 0)
|
||||
goto end;
|
||||
|
||||
if (subkey) {
|
||||
key9 = key9 * ( ((uint64_t)subkey << 16u) | ((uint16_t)~subkey + 2u) );
|
||||
}
|
||||
|
||||
key9--;
|
||||
key1 = (int)(((key9 >> 27) & 0x7fff));
|
||||
key2 = (int)(((key9 >> 12) & 0x7ffc) | 1);
|
||||
key3 = (int)(((key9 << 1 ) & 0x7fff) | 1);
|
||||
|
||||
/* alt from ADX_Decoder, probably the same */
|
||||
//key1 = ((key9 >> 27) & 0x7FFF);
|
||||
//key2 = ((key9 >> 12) & 0x7FFC) | 1;
|
||||
//key3 = ((key9 << 1 ) & 0x7FFE) | 1;
|
||||
//key2 |= key3 << 16;
|
||||
|
||||
end:
|
||||
*p_key1 = key1;
|
||||
*p_key2 = key2;
|
||||
*p_key3 = key3;
|
||||
}
|
||||
|
||||
int cri_key8_valid_keystring(uint8_t* buf, int buf_size) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < buf_size; i++) {
|
||||
if (buf[i] < 0x20 || buf[i] > 0x8f) { /* allow 0x8x for (uncommon) cases of SHIFT-JIS */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
13
src/util/cri_keys.h
Normal file
13
src/util/cri_keys.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef _CRI_KEYS_H_
|
||||
#define _CRI_KEYS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* common CRI key helpers */
|
||||
|
||||
void cri_key8_derive(const char* key8, uint16_t* p_key1, uint16_t* p_key2, uint16_t* p_key3);
|
||||
void cri_key9_derive(uint64_t key9, uint16_t subkey, uint16_t* p_key1, uint16_t* p_key2, uint16_t* p_key3);
|
||||
|
||||
int cri_key8_valid_keystring(uint8_t* buf, int buf_size);
|
||||
|
||||
#endif /* _CRI_KEYS_H_ */
|
@ -38,7 +38,6 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = {
|
||||
init_vgmstream_gcsw,
|
||||
init_vgmstream_ads,
|
||||
init_vgmstream_nps,
|
||||
init_vgmstream_rwsd,
|
||||
init_vgmstream_xa,
|
||||
init_vgmstream_rxws,
|
||||
init_vgmstream_ngc_dsp_stm,
|
||||
@ -542,10 +541,10 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = {
|
||||
|
||||
/* lowest priority metas (should go after all metas, and TXTH should go before raw formats) */
|
||||
init_vgmstream_txth, /* proper parsers should supersede TXTH, once added */
|
||||
init_vgmstream_dtk,
|
||||
init_vgmstream_dtk, /* semi-raw GC streamed files */
|
||||
init_vgmstream_mpeg, /* semi-raw MP3 */
|
||||
init_vgmstream_encrypted, /* encrypted stuff */
|
||||
init_vgmstream_btsnd, /* semi-headerless */
|
||||
init_vgmstream_encrypted, /* encrypted stuff */
|
||||
init_vgmstream_raw_int, /* .int raw PCM */
|
||||
init_vgmstream_ps_headerless, /* tries to detect a bunch of PS-ADPCM formats */
|
||||
init_vgmstream_raw_snds, /* .snds raw SNDS IMA */
|
||||
@ -560,6 +559,7 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = {
|
||||
init_vgmstream_ps2_adm, /* weird non-constant PSX blocks */
|
||||
init_vgmstream_baf_badrip, /* crap, to be removed */
|
||||
init_vgmstream_rxws_badrip, /* crap, to be removed */
|
||||
init_vgmstream_rwsd, /* crap, to be removed */
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
init_vgmstream_ffmpeg, /* may play anything incorrectly, since FFmpeg doesn't check extensions */
|
||||
#endif
|
||||
|
@ -325,9 +325,7 @@ typedef enum {
|
||||
meta_RWAV, /* contents of RWAR */
|
||||
meta_CWAV, /* contents of CWAR */
|
||||
meta_FWAV, /* contents of FWAR */
|
||||
meta_RSTM_SPM, /* RSTM with 44->22khz hack */
|
||||
meta_THP, /* THP movie files */
|
||||
meta_RSTM_shrunken, /* Atlus' mutant shortened RSTM */
|
||||
meta_SWAV,
|
||||
meta_NDS_RRDS, /* Ridge Racer DS */
|
||||
meta_WII_BNS, /* Wii BNS Banner Sound (similar to RSTM) */
|
||||
|
Loading…
x
Reference in New Issue
Block a user