mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-12-01 01:27:20 +01:00
Tweak block parsing to handle better unknown blocks; try to improve EOFs
This commit is contained in:
parent
a4d1e869cf
commit
e96f3c0700
@ -18,64 +18,59 @@ void ea_schl_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
|||||||
id = read_32bitBE(block_offset+0x00,streamFile);
|
id = read_32bitBE(block_offset+0x00,streamFile);
|
||||||
|
|
||||||
block_size = read_32bitLE(block_offset+0x04,streamFile);
|
block_size = read_32bitLE(block_offset+0x04,streamFile);
|
||||||
if (block_size > 0x00F00000) /* size size is always LE, except in early SS/MAC */
|
if (block_size > 0x00F00000) /* size is always LE, except in early SS/MAC */
|
||||||
block_size = read_32bitBE(block_offset+0x04,streamFile);
|
block_size = read_32bitBE(block_offset+0x04,streamFile);
|
||||||
|
|
||||||
if (id == 0x5343446C) /* "SCDl" data block found */
|
/* SCxx blocks have size in the header, but others may not. To simplify we just try to find
|
||||||
|
* a SCDl (main data) every 0x04. EA sometimes concats many small files, so after a SCEl (end block)
|
||||||
|
* there may be a new SCHl + SCDl too, so this pretends they are a single stream. */
|
||||||
|
if (id == 0x5343446C) { /* "SCDl" data block found */
|
||||||
|
|
||||||
|
/* use num_samples from header if possible; don't calc as data may have padding (ex. PCM8) or not possible (ex. MP3) */
|
||||||
|
switch(vgmstream->coding_type) {
|
||||||
|
case coding_PSX:
|
||||||
|
block_samples = ps_bytes_to_samples(block_size-0x10, vgmstream->channels);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
block_samples = read_32bit(block_offset+0x08,streamFile);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* guard against false positives (happens in "pIQT" blocks) */
|
||||||
|
if (block_size > 0xFFFF || block_samples > 0xFFFF) { /* observed max is ~0xf00 but who knows */
|
||||||
|
block_offset += 0x04;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
block_offset += block_size; /* size includes header */
|
|
||||||
|
|
||||||
/* Some EA files concat many small subfiles, for mapped music (.map/lin), so after SCEl
|
|
||||||
* there may be a new SCHl. We'll find it and pretend they are a single stream. */
|
|
||||||
if (id == 0x5343456C && block_offset + 0x80 > file_size) { /* "SCEl" end block found with no extra "SCHl" */
|
|
||||||
vgmstream->current_block_offset = block_offset;
|
|
||||||
vgmstream->next_block_offset = block_offset + block_size;
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
if (id == 0x5343456C) { /* "SCEl" end block found */
|
else {
|
||||||
/* Usually there is padding between SCEl and SCHl (aligned to 0x80) */
|
/* movie "pIQT" may be bigger than what block_size says, but seems to help */
|
||||||
block_offset += (block_offset % 0x04) == 0 ? 0 : 0x04 - (block_offset % 0x04); /* also 32b-aligned */
|
if (id == 0x5343486C || id == 0x5343436C || id == 0x53434C6C || id == 0x70495154) { /* "SCHl" "SCCl" "SCLl" "SCEl" "pIQT" */
|
||||||
for (i = 0; i < 0x80 / 4; i++) {
|
block_offset += block_size;
|
||||||
id = read_32bitBE(block_offset,streamFile);
|
} else {
|
||||||
if (id == 0x5343486C) /* "SCHl" new header block found */
|
|
||||||
break; /* next loop will parse and skip it */
|
|
||||||
block_offset += 0x04;
|
block_offset += 0x04;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (block_offset >= file_size) {
|
if (id == 0x5343456C) { /* "SCEl" end block found */
|
||||||
vgmstream->current_block_offset = block_offset;
|
block_offset += (block_offset % 0x04) == 0 ? 0 : 0x04 - (block_offset % 0x04); /* 32b-aligned, important */
|
||||||
vgmstream->next_block_offset = block_offset + 0x04;
|
/* Usually there is padding between SCEl and SCHl too (aligned to 0x80) */
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (id == 0 || id == 0xFFFFFFFF) {
|
continue;
|
||||||
vgmstream->current_block_offset = block_offset;
|
|
||||||
vgmstream->next_block_offset = block_offset + 0x04;
|
|
||||||
return; /* probably hit padding or EOF */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* EOF reads: pretend we have samples to please the layout (unsure if this helps) */
|
||||||
if (block_offset >= file_size) {
|
if (block_offset >= file_size) {
|
||||||
vgmstream->current_block_offset = block_offset;
|
vgmstream->current_block_offset = block_offset;
|
||||||
vgmstream->next_block_offset = block_offset + 0x04;
|
vgmstream->next_block_offset = block_offset + 0x04;
|
||||||
|
vgmstream->current_block_samples = vgmstream->num_samples;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* use num_samples from header if possible; don't calc as rarely data may have padding (ex. PCM8) or not possible (ex. MP3) */
|
|
||||||
switch(vgmstream->coding_type) {
|
|
||||||
case coding_PSX:
|
|
||||||
block_samples = ps_bytes_to_samples(block_size-0x10, vgmstream->channels);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
block_samples = read_32bit(block_offset+0x08,streamFile);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* set new channel offsets and ADPCM history */
|
/* set new channel offsets and ADPCM history */
|
||||||
/* ADPCM hist could be considered part of the stream/decoder (some EAXA decoders call it "EAXA R1" when it has hist), and BNKs
|
/* ADPCM hist could be considered part of the stream/decoder (some EAXA decoders call it "EAXA R1" when it has hist), and BNKs
|
||||||
* (with no blocks) also have them in the first offset. To simplify and since DSP also have them, we read them here instead. */
|
* (with no blocks) also have them in the first offset. To simplify and since DSP also have them, we read them here instead. */
|
||||||
|
@ -296,6 +296,7 @@ static int parse_stream_header(STREAMFILE* streamFile, ea_header* ea, off_t begi
|
|||||||
case 0x0B: /* unknown (always 0x02) */
|
case 0x0B: /* unknown (always 0x02) */
|
||||||
case 0x13: /* effect bus (0..127) */
|
case 0x13: /* effect bus (0..127) */
|
||||||
case 0x14: /* emdedded user data (free size/value) */
|
case 0x14: /* emdedded user data (free size/value) */
|
||||||
|
case 0x1B: /* unknown (movie related?) */
|
||||||
read_patch(streamFile, &offset);
|
read_patch(streamFile, &offset);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -527,13 +528,13 @@ fail:
|
|||||||
* music (.map/lin). We get total possible samples (counting all subfiles) and pretend
|
* music (.map/lin). We get total possible samples (counting all subfiles) and pretend
|
||||||
* they are a single stream. Subfiles always share header, except num_samples. */
|
* they are a single stream. Subfiles always share header, except num_samples. */
|
||||||
static int get_ea_total_samples(STREAMFILE* streamFile, off_t start_offset, const ea_header* ea) {
|
static int get_ea_total_samples(STREAMFILE* streamFile, off_t start_offset, const ea_header* ea) {
|
||||||
int i, num_samples = 0;
|
int num_samples = 0;
|
||||||
size_t file_size = get_streamfile_size(streamFile);
|
size_t file_size = get_streamfile_size(streamFile);
|
||||||
off_t block_offset = start_offset;
|
off_t block_offset = start_offset;
|
||||||
int32_t (*read_32bit)(off_t,STREAMFILE*) = ea->big_endian ? read_32bitBE : read_32bitLE;
|
int32_t (*read_32bit)(off_t,STREAMFILE*) = ea->big_endian ? read_32bitBE : read_32bitLE;
|
||||||
|
|
||||||
while (block_offset < file_size) {
|
while (block_offset < file_size) {
|
||||||
uint32_t id, block_size;
|
uint32_t id, block_size, block_samples;
|
||||||
|
|
||||||
id = read_32bitBE(block_offset+0x00,streamFile);
|
id = read_32bitBE(block_offset+0x00,streamFile);
|
||||||
|
|
||||||
@ -541,44 +542,48 @@ static int get_ea_total_samples(STREAMFILE* streamFile, off_t start_offset, cons
|
|||||||
if (block_size > 0x00F00000) /* size is always LE, except in early SS/MAC */
|
if (block_size > 0x00F00000) /* size is always LE, except in early SS/MAC */
|
||||||
block_size = read_32bitBE(block_offset+0x04,streamFile);
|
block_size = read_32bitBE(block_offset+0x04,streamFile);
|
||||||
|
|
||||||
|
/* SCxx blocks have size in the header, but others may not. To simplify we just try to
|
||||||
|
* find a SCDl (main data) every 0x04. EA sometimes concats many small files, so after a SCEl (end block)
|
||||||
|
* there may be a new SCHl + SCDl too, so this pretends they are a single stream. */
|
||||||
if (id == 0x5343446C) { /* "SCDl" data block found */
|
if (id == 0x5343446C) { /* "SCDl" data block found */
|
||||||
|
|
||||||
/* use num_samples from header if possible */
|
/* use num_samples from header if possible */
|
||||||
switch (ea->codec2) {
|
switch (ea->codec2) {
|
||||||
case EA_CODEC2_VAG: /* PS-ADPCM */
|
case EA_CODEC2_VAG: /* PS-ADPCM */
|
||||||
num_samples += ps_bytes_to_samples(block_size-0x10, ea->channels);
|
block_samples = ps_bytes_to_samples(block_size-0x10, ea->channels);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
num_samples += read_32bit(block_offset+0x08,streamFile);
|
block_samples = read_32bit(block_offset+0x08,streamFile);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* guard against false positives (happens in "pIQT" blocks) */
|
||||||
|
if (block_size > 0xFFFF || block_samples > 0xFFFF) { /* observed max is ~0xf00 but who knows */
|
||||||
|
block_offset += 0x04;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
num_samples += block_samples;
|
||||||
|
|
||||||
|
block_offset += block_size; /* size includes header */
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
block_offset += block_size; /* size includes header */
|
/* movie "pIQT" may be bigger than what block_size says, but seems to help */
|
||||||
|
if (id == 0x5343486C || id == 0x5343436C || id == 0x53434C6C || id == 0x70495154) { /* "SCHl" "SCCl" "SCLl" "SCEl" "pIQT" */
|
||||||
/* EA sometimes concats many small files, so after SCEl there may be a new SCHl.
|
block_offset += block_size;
|
||||||
* We'll find it and pretend they are a single stream. */
|
} else {
|
||||||
if (id == 0x5343456C && block_offset + 0x80 > file_size)
|
|
||||||
break;
|
|
||||||
if (id == 0x5343456C) { /* "SCEl" end block found */
|
|
||||||
/* Usually there is padding between SCEl and SCHl (aligned to 0x80) */
|
|
||||||
block_offset += (block_offset % 0x04) == 0 ? 0 : 0x04 - (block_offset % 0x04); /* also 32b-aligned */
|
|
||||||
for (i = 0; i < 0x80 / 4; i++) {
|
|
||||||
id = read_32bitBE(block_offset,streamFile);
|
|
||||||
if (id == 0x5343486C) /* "SCHl" new header block found */
|
|
||||||
break; /* next loop will parse and skip it */
|
|
||||||
block_offset += 0x04;
|
block_offset += 0x04;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (id == 0x5343456C) { /* "SCEl" end block found */
|
||||||
|
/* Usually there is padding between SCEl and SCHl (aligned to 0x80) */
|
||||||
|
block_offset += (block_offset % 0x04) == 0 ? 0 : 0x04 - (block_offset % 0x04); /* also 32b-aligned, important */
|
||||||
|
}
|
||||||
|
|
||||||
|
block_offset += 0x04;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (block_offset > file_size)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (id == 0 || id == 0xFFFFFFFF)
|
|
||||||
return num_samples; /* probably hit padding or EOF */
|
|
||||||
|
|
||||||
VGM_ASSERT(id != 0x5343486C && id != 0x5343436C && id != 0x5343446C && id != 0x53434C6C && id != 0x5343456C,
|
|
||||||
"EA: unknown block id 0x%x at 0x%lx\n", id, block_offset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return num_samples;
|
return num_samples;
|
||||||
|
Loading…
Reference in New Issue
Block a user