mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-12-19 09:55:53 +01:00
185 lines
6.2 KiB
C
185 lines
6.2 KiB
C
#include "deblock_streamfile.h"
|
|
|
|
//todo move to utils or something
|
|
|
|
static void block_callback_default(STREAMFILE* sf, deblock_io_data* data) {
|
|
data->block_size = data->cfg.chunk_size;
|
|
data->skip_size = data->cfg.skip_size;
|
|
data->data_size = data->block_size - data->skip_size;
|
|
|
|
//;VGM_LOG("DEBLOCK: of=%lx, bs=%lx, ss=%lx, ds=%lx\n", data->physical_offset, data->block_size, data->skip_size, data->data_size);
|
|
}
|
|
|
|
static size_t deblock_io_read(STREAMFILE* sf, uint8_t* dest, off_t offset, size_t length, deblock_io_data* data) {
|
|
size_t total_read = 0;
|
|
|
|
//;VGM_LOG("DEBLOCK: of=%lx, sz=%x, po=%lx\n", offset, length, data->physical_offset);
|
|
|
|
/* re-start when previous offset (can't map logical<>physical offsets) */
|
|
if (data->logical_offset < 0 || offset < data->logical_offset) {
|
|
;VGM_LOG("DEBLOCK: restart offset=%lx + %x, po=%lx, lo=%lx\n", offset, length, data->physical_offset, data->logical_offset);
|
|
data->physical_offset = data->cfg.stream_start;
|
|
data->logical_offset = 0x00;
|
|
data->block_size = 0;
|
|
data->data_size = 0;
|
|
data->skip_size = 0;
|
|
|
|
data->step_count = data->cfg.step_start;
|
|
//data->read_count = data->cfg.read_count;
|
|
}
|
|
|
|
/* read blocks */
|
|
while (length > 0) {
|
|
|
|
/* ignore EOF */
|
|
if (offset < 0 ||
|
|
(data->physical_offset >= data->cfg.stream_start + data->physical_size) ||
|
|
(data->logical_size > 0 && offset > data->logical_size)) {
|
|
break;
|
|
}
|
|
|
|
/* process new block */
|
|
if (data->data_size <= 0) {
|
|
data->cfg.block_callback(sf, data);
|
|
|
|
if (data->block_size <= 0) {
|
|
VGM_LOG("DEBLOCK: block size not set at %lx\n", data->physical_offset);
|
|
break;
|
|
}
|
|
}
|
|
|
|
#if 1
|
|
if (data->step_count > 0) {
|
|
data->step_count--;
|
|
data->physical_offset += data->block_size;
|
|
data->data_size = 0;
|
|
continue;
|
|
}
|
|
#else
|
|
/* handle blocks from multiple streams */
|
|
{
|
|
if (data->step_count > 0) {
|
|
data->step_count--;
|
|
data->data_size = 0; /* step over this block */
|
|
}
|
|
else if (data->read_count) {//must detect when blocks has been read
|
|
data->read_count--; /* read this block */
|
|
|
|
/* reset */
|
|
if (data->step_count == 0 && data->read_count == 0) {
|
|
data->step_count = data->cfg.step_count;
|
|
data->read_count = data->cfg.read_count;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
/* move to next block */
|
|
if (data->data_size == 0 || offset >= data->logical_offset + data->data_size) {
|
|
data->physical_offset += data->block_size;
|
|
data->logical_offset += data->data_size;
|
|
data->data_size = 0;
|
|
|
|
data->step_count = data->cfg.step_count;
|
|
//VGM_LOG("ignore at %lx + %lx, skips=%i\n", data->physical_offset, data->block_size, data->step_count);
|
|
continue;
|
|
}
|
|
|
|
//;VGM_LOG("accept at %lx + %lx, skips=%i\n", data->physical_offset, data->block_size, data->step_count);
|
|
|
|
/* read block data */
|
|
{
|
|
size_t bytes_consumed, bytes_done, to_read;
|
|
|
|
bytes_consumed = offset - data->logical_offset;
|
|
to_read = data->data_size - bytes_consumed;
|
|
if (to_read > length)
|
|
to_read = length;
|
|
bytes_done = read_streamfile(dest, data->physical_offset + data->skip_size + bytes_consumed, to_read, sf);
|
|
|
|
if (data->cfg.read_callback) {
|
|
data->cfg.read_callback(dest, data, bytes_consumed, bytes_done);
|
|
}
|
|
|
|
total_read += bytes_done;
|
|
dest += bytes_done;
|
|
offset += bytes_done;
|
|
length -= bytes_done;
|
|
|
|
if (bytes_done != to_read || bytes_done == 0) {
|
|
break; /* error/EOF */
|
|
}
|
|
}
|
|
}
|
|
|
|
return total_read;
|
|
}
|
|
|
|
static size_t deblock_io_size(STREAMFILE* sf, deblock_io_data* data) {
|
|
uint8_t buf[0x04];
|
|
|
|
if (data->logical_size)
|
|
return data->logical_size;
|
|
|
|
if (data->cfg.logical_size) {
|
|
data->logical_size = data->cfg.logical_size;
|
|
return data->logical_size;
|
|
}
|
|
|
|
/* force a fake read at max offset, to get max logical_offset (will be reset next read) */
|
|
deblock_io_read(sf, buf, 0x7FFFFFFF, 1, data);
|
|
data->logical_size = data->logical_offset;
|
|
|
|
//todo tests:
|
|
//if (logical_size > max_physical_offset)
|
|
// return 0;
|
|
//if (logical_size != data->stream_size)
|
|
// return 0;
|
|
|
|
|
|
return data->logical_size;
|
|
}
|
|
|
|
/* generic "de-blocker" helper for streams divided in blocks that have weird interleaves, their
|
|
* decoder can't easily use blocked layout, or some other weird feature. It "filters" data so
|
|
* reader only sees clean data without blocks. Must pass setup config and a callback that sets
|
|
* sizes of a single block. */
|
|
STREAMFILE* open_io_deblock_streamfile_f(STREAMFILE* sf, deblock_config_t *cfg) {
|
|
STREAMFILE* new_sf = NULL;
|
|
deblock_io_data io_data = {0};
|
|
|
|
/* prepare data */
|
|
io_data.cfg = *cfg; /* memcpy */
|
|
|
|
if (io_data.cfg.block_callback == NULL)
|
|
io_data.cfg.block_callback = block_callback_default;
|
|
|
|
if (io_data.cfg.stream_start < 0)
|
|
goto fail;
|
|
if (io_data.cfg.step_start < 0 || io_data.cfg.step_count < 0)
|
|
goto fail;
|
|
|
|
if (io_data.cfg.step_count > 0) {
|
|
io_data.cfg.step_count--;
|
|
}
|
|
/*
|
|
if (io_data.cfg.read_count == 0)
|
|
io_data.cfg.read_count = 1;
|
|
*/
|
|
io_data.physical_size = io_data.cfg.stream_size;
|
|
if (io_data.physical_size > get_streamfile_size(sf) + io_data.cfg.stream_start || io_data.physical_size == 0)
|
|
io_data.physical_size = get_streamfile_size(sf) - io_data.cfg.stream_start;
|
|
io_data.physical_end = io_data.cfg.stream_start + io_data.physical_size;
|
|
|
|
io_data.logical_offset = -1; /* read reset */
|
|
|
|
//TODO: other validations
|
|
|
|
/* setup subfile */
|
|
new_sf = open_io_streamfile_f(sf, &io_data, sizeof(deblock_io_data), deblock_io_read, deblock_io_size);
|
|
return new_sf;
|
|
fail:
|
|
VGM_LOG("DEBLOCK: bad init\n");
|
|
close_streamfile(sf);
|
|
return NULL;
|
|
}
|