mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-28 08:20:54 +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);
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
|
||||
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 */
|
||||
/* 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 */
|
||||
else {
|
||||
/* 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" */
|
||||
block_offset += block_size;
|
||||
} else {
|
||||
block_offset += 0x04;
|
||||
}
|
||||
}
|
||||
|
||||
if (block_offset >= file_size) {
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
vgmstream->next_block_offset = block_offset + 0x04;
|
||||
return;
|
||||
}
|
||||
if (id == 0x5343456C) { /* "SCEl" end block found */
|
||||
block_offset += (block_offset % 0x04) == 0 ? 0 : 0x04 - (block_offset % 0x04); /* 32b-aligned, important */
|
||||
/* Usually there is padding between SCEl and SCHl too (aligned to 0x80) */
|
||||
}
|
||||
|
||||
if (id == 0 || id == 0xFFFFFFFF) {
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
vgmstream->next_block_offset = block_offset + 0x04;
|
||||
return; /* probably hit padding or EOF */
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* EOF reads: pretend we have samples to please the layout (unsure if this helps) */
|
||||
if (block_offset >= file_size) {
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
vgmstream->next_block_offset = block_offset + 0x04;
|
||||
vgmstream->current_block_samples = vgmstream->num_samples;
|
||||
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 */
|
||||
/* 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. */
|
||||
|
@ -296,6 +296,7 @@ static int parse_stream_header(STREAMFILE* streamFile, ea_header* ea, off_t begi
|
||||
case 0x0B: /* unknown (always 0x02) */
|
||||
case 0x13: /* effect bus (0..127) */
|
||||
case 0x14: /* emdedded user data (free size/value) */
|
||||
case 0x1B: /* unknown (movie related?) */
|
||||
read_patch(streamFile, &offset);
|
||||
break;
|
||||
|
||||
@ -527,13 +528,13 @@ fail:
|
||||
* 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. */
|
||||
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);
|
||||
off_t block_offset = start_offset;
|
||||
int32_t (*read_32bit)(off_t,STREAMFILE*) = ea->big_endian ? read_32bitBE : read_32bitLE;
|
||||
|
||||
while (block_offset < file_size) {
|
||||
uint32_t id, block_size;
|
||||
uint32_t id, block_size, block_samples;
|
||||
|
||||
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 */
|
||||
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 */
|
||||
|
||||
/* use num_samples from header if possible */
|
||||
switch (ea->codec2) {
|
||||
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;
|
||||
|
||||
default:
|
||||
num_samples += read_32bit(block_offset+0x08,streamFile);
|
||||
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;
|
||||
}
|
||||
|
||||
num_samples += block_samples;
|
||||
|
||||
block_offset += block_size; /* size includes header */
|
||||
}
|
||||
|
||||
block_offset += block_size; /* size includes header */
|
||||
|
||||
/* EA sometimes concats many small files, 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)
|
||||
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 */
|
||||
else {
|
||||
/* 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" */
|
||||
block_offset += block_size;
|
||||
} else {
|
||||
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;
|
||||
|
Loading…
Reference in New Issue
Block a user