mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-01-17 23:36:41 +01:00
Change AIX to use custom io and layered+segmented layout
Resulting output is slightly different because AIX layout used to carry ADX ADPCM hist between segments, but since ADX does have hist in header (not parsed when AIX was implemented) this step is unneeded/incorrect
This commit is contained in:
parent
f354a8fb88
commit
6bd23fe948
293
src/meta/aix.c
293
src/meta/aix.c
@ -1,200 +1,183 @@
|
||||
#include "meta.h"
|
||||
#include "../layout/layout.h"
|
||||
#include "aix_streamfile.h"
|
||||
|
||||
/* AIX - interleaved AAX, N segments with M layers (1/2ch) inside [SoulCalibur IV (PS3), Dragon Ball Z: Burst Limit (PS3)] */
|
||||
VGMSTREAM * init_vgmstream_aix(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
STREAMFILE * streamFileAIX = NULL;
|
||||
int loop_flag = 0, channel_count, sample_rate;
|
||||
int32_t sample_count, loop_start_sample = 0, loop_end_sample = 0;
|
||||
|
||||
off_t *segment_offset = NULL;
|
||||
int32_t *segment_samples = NULL;
|
||||
aix_codec_data *data = NULL;
|
||||
#define MAX_SEGMENTS 10 /* usually segment0=intro, segment1=loop/main, sometimes ~5 */
|
||||
|
||||
static VGMSTREAM *build_segmented_vgmstream(STREAMFILE *streamFile, off_t *segment_offsets, size_t *segment_sizes, int32_t *segment_samples, int segment_count, int layer_count);
|
||||
|
||||
/* AIX - N segments with M layers (2ch ADX) inside [SoulCalibur IV (PS3), Dragon Ball Z: Burst Limit (PS3)] */
|
||||
VGMSTREAM * init_vgmstream_aix(STREAMFILE *sf) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
|
||||
off_t segment_offsets[MAX_SEGMENTS] = {0};
|
||||
size_t segment_sizes[MAX_SEGMENTS] = {0};
|
||||
int32_t segment_samples[MAX_SEGMENTS] = {0};
|
||||
int segment_rates[MAX_SEGMENTS] = {0};
|
||||
|
||||
off_t data_offset;
|
||||
off_t layer_list_offset;
|
||||
off_t layer_list_end;
|
||||
const off_t segment_list_offset = 0x20;
|
||||
const size_t segment_list_entry_size = 0x10;
|
||||
const size_t layer_list_entry_size = 0x08;
|
||||
|
||||
int segment_count, layer_count;
|
||||
int i, j;
|
||||
int i;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "aix"))
|
||||
if (!check_extensions(sf, "aix"))
|
||||
goto fail;
|
||||
if (read_32bitBE(0x00,streamFile) != 0x41495846 || /* "AIXF" */
|
||||
read_32bitBE(0x08,streamFile) != 0x01000014 || /* version? */
|
||||
read_32bitBE(0x0c,streamFile) != 0x00000800)
|
||||
if (read_u32be(0x00,sf) != 0x41495846 || /* "AIXF" */
|
||||
read_u32be(0x08,sf) != 0x01000014 || /* version? */
|
||||
read_u32be(0x0c,sf) != 0x00000800)
|
||||
goto fail;
|
||||
|
||||
/* AIX combine layers for multichannel and segments for looping, all very hacky.
|
||||
* For some reason AIX with 1 layer and 1 segment exist (equivalent to a single ADX). */
|
||||
|
||||
/* base segment header */
|
||||
data_offset = read_32bitBE(0x04,streamFile)+0x08;
|
||||
|
||||
segment_count = (uint16_t)read_16bitBE(0x18,streamFile);
|
||||
if (segment_count < 1) goto fail;
|
||||
|
||||
layer_list_offset = segment_list_offset + segment_count*segment_list_entry_size + 0x10;
|
||||
if (layer_list_offset >= data_offset) goto fail;
|
||||
|
||||
segment_samples = calloc(segment_count,sizeof(int32_t));
|
||||
if (!segment_samples) goto fail;
|
||||
segment_offset = calloc(segment_count,sizeof(off_t));
|
||||
if (!segment_offset) goto fail;
|
||||
data_offset = read_s32be(0x04,sf) + 0x08;
|
||||
|
||||
/* parse segments table */
|
||||
{
|
||||
sample_rate = read_32bitBE(layer_list_offset+0x08,streamFile); /* first layer's sample rate */
|
||||
const off_t segment_list_offset = 0x20;
|
||||
const size_t segment_list_entry_size = 0x10;
|
||||
|
||||
segment_count = read_u16be(0x18,sf);
|
||||
|
||||
if (segment_count < 1 || segment_count > MAX_SEGMENTS) goto fail;
|
||||
|
||||
layer_list_offset = segment_list_offset + segment_count*segment_list_entry_size + 0x10;
|
||||
if (layer_list_offset >= data_offset) goto fail;
|
||||
|
||||
for (i = 0; i < segment_count; i++) {
|
||||
segment_offset[i] = read_32bitBE(segment_list_offset + segment_list_entry_size*i + 0x00,streamFile);
|
||||
/* 0x04: segment size */
|
||||
segment_samples[i] = read_32bitBE(segment_list_offset + segment_list_entry_size*i + 0x08,streamFile);
|
||||
segment_offsets[i] = read_s32be(segment_list_offset + segment_list_entry_size*i + 0x00,sf);
|
||||
segment_sizes[i] = read_u32be(segment_list_offset + segment_list_entry_size*i + 0x04,sf);
|
||||
segment_samples[i] = read_s32be(segment_list_offset + segment_list_entry_size*i + 0x08,sf);
|
||||
segment_rates[i] = read_s32be(segment_list_offset + segment_list_entry_size*i + 0x0c,sf);
|
||||
|
||||
/* segments > 0 can have 0 sample rate, seems to indicate same as first
|
||||
* [Ryu ga Gotoku: Kenzan! (PS3) tenkei_sng1.aix] */
|
||||
if (i > 0 && segment_rates[i] == 0)
|
||||
segment_rates[i] = segment_rates[0];
|
||||
|
||||
/* all segments must have equal sample rate */
|
||||
if (read_32bitBE(segment_list_offset + segment_list_entry_size*i + 0x0c,streamFile) != sample_rate) {
|
||||
/* segments > 0 can have 0 sample rate (Ryu ga gotoku: Kenzan! tenkei_sng1.aix),
|
||||
seems to indicate same sample rate as first */
|
||||
if (!(i > 0 && read_32bitBE(segment_list_offset + segment_list_entry_size*i + 0x0c,streamFile) == 0))
|
||||
goto fail;
|
||||
}
|
||||
if (segment_rates[i] != segment_rates[0])
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (segment_offset[0] != data_offset)
|
||||
if (segment_offsets[0] != data_offset)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* base layer header */
|
||||
layer_count = (uint8_t)read_8bit(layer_list_offset,streamFile);
|
||||
if (layer_count < 1) goto fail;
|
||||
|
||||
layer_list_end = layer_list_offset + 0x08 + layer_count*layer_list_entry_size;
|
||||
if (layer_list_end >= data_offset) goto fail;
|
||||
|
||||
/* parse layers table */
|
||||
channel_count = 0;
|
||||
for (i = 0; i < layer_count; i++) {
|
||||
/* all streams must have same samplerate as segments */
|
||||
if (read_32bitBE(layer_list_offset + 0x08 + i*layer_list_entry_size + 0x00,streamFile) != sample_rate)
|
||||
goto fail;
|
||||
channel_count += read_8bit(layer_list_offset + 0x08 + i*layer_list_entry_size + 0x04,streamFile);
|
||||
}
|
||||
{
|
||||
const size_t layer_list_entry_size = 0x08;
|
||||
|
||||
/* check for existence of segments */
|
||||
for (i = 0; i < segment_count; i++) {
|
||||
off_t aixp_offset = segment_offset[i];
|
||||
for (j = 0; j < layer_count; j++) {
|
||||
if (read_32bitBE(aixp_offset,streamFile) != 0x41495850) /* "AIXP" */
|
||||
layer_count = read_u8(layer_list_offset,sf);
|
||||
if (layer_count < 1) goto fail;
|
||||
|
||||
layer_list_end = layer_list_offset + 0x08 + layer_count*layer_list_entry_size;
|
||||
if (layer_list_end >= data_offset) goto fail;
|
||||
|
||||
for (i = 0; i < layer_count; i++) {
|
||||
/* all layers must have same sample rate as segments */
|
||||
if (read_s32be(layer_list_offset + 0x08 + i*layer_list_entry_size + 0x00,sf) != segment_rates[0])
|
||||
goto fail;
|
||||
if (read_8bit(aixp_offset+0x08,streamFile) != j)
|
||||
goto fail;
|
||||
aixp_offset += read_32bitBE(aixp_offset+0x04,streamFile) + 0x08;
|
||||
/* 0x04: layer channels */
|
||||
}
|
||||
}
|
||||
|
||||
/* open base streamfile, that will be shared by all open_aix_with_STREAMFILE */
|
||||
{
|
||||
char filename[PATH_LIMIT];
|
||||
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
streamFileAIX = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); //todo simplify
|
||||
if (!streamFileAIX) goto fail;
|
||||
}
|
||||
|
||||
/* init layout */
|
||||
{
|
||||
data = malloc(sizeof(aix_codec_data));
|
||||
if (!data) goto fail;
|
||||
|
||||
data->segment_count = segment_count;
|
||||
data->stream_count = layer_count;
|
||||
data->adxs = calloc(segment_count * layer_count, sizeof(VGMSTREAM*));
|
||||
if (!data->adxs) goto fail;
|
||||
|
||||
data->sample_counts = calloc(segment_count,sizeof(int32_t));
|
||||
if (!data->sample_counts) goto fail;
|
||||
|
||||
memcpy(data->sample_counts,segment_samples,segment_count*sizeof(int32_t));
|
||||
}
|
||||
|
||||
/* open each segment / layer subfile */
|
||||
for (i = 0; i < segment_count; i++) {
|
||||
for (j = 0; j < layer_count; j++) {
|
||||
//;VGM_LOG("AIX: opening segment %d/%d stream %d/%d %x\n",i,segment_count,j,stream_count,segment_offset[i]);
|
||||
VGMSTREAM *temp_vgmstream;
|
||||
STREAMFILE * temp_streamFile = open_aix_with_STREAMFILE(streamFileAIX,segment_offset[i],j);
|
||||
if (!temp_streamFile) goto fail;
|
||||
|
||||
temp_vgmstream = data->adxs[i*layer_count+j] = init_vgmstream_adx(temp_streamFile);
|
||||
|
||||
close_streamfile(temp_streamFile);
|
||||
|
||||
if (!temp_vgmstream) goto fail;
|
||||
|
||||
/* setup layers */
|
||||
if (temp_vgmstream->num_samples != data->sample_counts[i] || temp_vgmstream->loop_flag != 0)
|
||||
goto fail;
|
||||
|
||||
setup_vgmstream(temp_vgmstream); /* final setup as the VGMSTREAM was created manually */
|
||||
}
|
||||
}
|
||||
|
||||
/* get looping and samples */
|
||||
sample_count = 0;
|
||||
loop_flag = (segment_count > 1);
|
||||
for (i = 0; i < segment_count; i++) {
|
||||
sample_count += data->sample_counts[i];
|
||||
|
||||
if (i == 0)
|
||||
loop_start_sample = sample_count;
|
||||
if (i == 1)
|
||||
loop_end_sample = sample_count;
|
||||
}
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
/* build combo layers + segments VGMSTREAM */
|
||||
vgmstream = build_segmented_vgmstream(sf, segment_offsets, segment_sizes, segment_samples, segment_count, layer_count);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
vgmstream->num_samples = sample_count;
|
||||
vgmstream->loop_start_sample = loop_start_sample;
|
||||
vgmstream->loop_end_sample = loop_end_sample;
|
||||
|
||||
vgmstream->meta_type = meta_AIX;
|
||||
vgmstream->coding_type = data->adxs[0]->coding_type;
|
||||
vgmstream->layout_type = layout_aix;
|
||||
|
||||
vgmstream->ch[0].streamfile = streamFileAIX;
|
||||
data->current_segment = 0;
|
||||
|
||||
vgmstream->codec_data = data;
|
||||
free(segment_offset);
|
||||
free(segment_samples);
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_streamfile(streamFileAIX);
|
||||
close_vgmstream(vgmstream);
|
||||
free(segment_samples);
|
||||
free(segment_offset);
|
||||
|
||||
/* free aix layout */
|
||||
if (data) {
|
||||
if (data->adxs) {
|
||||
int i;
|
||||
for (i = 0; i < data->segment_count*data->stream_count; i++) {
|
||||
close_vgmstream(data->adxs[i]);
|
||||
}
|
||||
free(data->adxs);
|
||||
}
|
||||
if (data->sample_counts) {
|
||||
free(data->sample_counts);
|
||||
}
|
||||
free(data);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static VGMSTREAM *build_layered_vgmstream(STREAMFILE *streamFile, off_t segment_offset, size_t segment_size, int layer_count) {
|
||||
VGMSTREAM *vgmstream;
|
||||
layered_layout_data* data = NULL;
|
||||
int i;
|
||||
STREAMFILE* temp_streamFile = NULL;
|
||||
|
||||
|
||||
/* build layers */
|
||||
data = init_layout_layered(layer_count);
|
||||
if (!data) goto fail;
|
||||
|
||||
for (i = 0; i < layer_count; i++) {
|
||||
/* build the layer STREAMFILE */
|
||||
temp_streamFile = setup_aix_streamfile(streamFile, segment_offset, segment_size, i, "adx");
|
||||
if (!temp_streamFile) goto fail;
|
||||
|
||||
/* build the sub-VGMSTREAM */
|
||||
data->layers[i] = init_vgmstream_adx(temp_streamFile);
|
||||
if (!data->layers[i]) goto fail;
|
||||
|
||||
data->layers[i]->stream_size = segment_size;
|
||||
|
||||
close_streamfile(temp_streamFile);
|
||||
temp_streamFile = NULL;
|
||||
}
|
||||
|
||||
if (!setup_layout_layered(data))
|
||||
goto fail;
|
||||
|
||||
|
||||
/* build the layered VGMSTREAM */
|
||||
vgmstream = allocate_layered_vgmstream(data);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
if (!vgmstream) free_layout_layered(data);
|
||||
close_vgmstream(vgmstream);
|
||||
close_streamfile(temp_streamFile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static VGMSTREAM *build_segmented_vgmstream(STREAMFILE *streamFile, off_t *segment_offsets, size_t *segment_sizes, int32_t *segment_samples, int segment_count, int layer_count) {
|
||||
VGMSTREAM *vgmstream;
|
||||
segmented_layout_data *data = NULL;
|
||||
int i, loop_flag, loop_start_segment, loop_end_segment;
|
||||
|
||||
|
||||
/* build segments */
|
||||
data = init_layout_segmented(segment_count);
|
||||
if (!data) goto fail;
|
||||
|
||||
for (i = 0; i < segment_count; i++) {
|
||||
/* build the layered sub-VGMSTREAM */
|
||||
data->segments[i] = build_layered_vgmstream(streamFile, segment_offsets[i], segment_sizes[i], layer_count);
|
||||
if (!data->segments[i]) goto fail;
|
||||
|
||||
data->segments[i]->num_samples = segment_samples[i]; /* just in case */
|
||||
}
|
||||
|
||||
if (!setup_layout_segmented(data))
|
||||
goto fail;
|
||||
|
||||
loop_flag = (segment_count > 0);
|
||||
loop_start_segment = 1;
|
||||
loop_end_segment = 1; /* looks correct in some games (DBZ: Burst Limit, Metroid: Other M) */
|
||||
|
||||
/* build the segmented VGMSTREAM */
|
||||
vgmstream = allocate_segmented_vgmstream(data, loop_flag, loop_start_segment, loop_end_segment);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
if (!vgmstream) free_layout_segmented(data);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -2,163 +2,142 @@
|
||||
#define _AIX_STREAMFILE_H_
|
||||
#include "../streamfile.h"
|
||||
|
||||
/* a streamfile representing a subfile inside another, in blocked AIX format */
|
||||
|
||||
typedef struct _AIXSTREAMFILE {
|
||||
STREAMFILE sf;
|
||||
STREAMFILE *real_file;
|
||||
off_t start_physical_offset;
|
||||
off_t current_physical_offset;
|
||||
off_t current_logical_offset;
|
||||
off_t current_block_size;
|
||||
int stream_id;
|
||||
} AIXSTREAMFILE;
|
||||
typedef struct {
|
||||
/* config */
|
||||
off_t stream_offset;
|
||||
size_t stream_size;
|
||||
int layer_number;
|
||||
|
||||
/* state */
|
||||
off_t logical_offset; /* fake offset */
|
||||
off_t physical_offset; /* actual offset */
|
||||
size_t block_size; /* current size */
|
||||
size_t skip_size; /* size from block start to reach data */
|
||||
size_t data_size; /* usable size in a block */
|
||||
|
||||
size_t logical_size;
|
||||
} aix_io_data;
|
||||
|
||||
|
||||
/*static*/ STREAMFILE *open_aix_with_STREAMFILE(STREAMFILE *file, off_t start_offset, int stream_id);
|
||||
static size_t aix_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, aix_io_data* data) {
|
||||
size_t total_read = 0;
|
||||
|
||||
|
||||
static size_t read_aix(AIXSTREAMFILE *streamfile,uint8_t *dest,off_t offset,size_t length) {
|
||||
size_t sz = 0;
|
||||
/* re-start when previous offset (can't map logical<>physical offsets) */
|
||||
if (data->logical_offset < 0 || offset < data->logical_offset) {
|
||||
data->physical_offset = data->stream_offset;
|
||||
data->logical_offset = 0x00;
|
||||
data->data_size = 0;
|
||||
}
|
||||
|
||||
/*printf("trying to read %x bytes from %x (str%d)\n",length,offset,streamfile->stream_id);*/
|
||||
/* read blocks */
|
||||
while (length > 0) {
|
||||
int read_something = 0;
|
||||
|
||||
/* read the beginning of the requested block, if we can */
|
||||
if (offset >= streamfile->current_logical_offset) {
|
||||
off_t to_read;
|
||||
off_t length_available;
|
||||
/* ignore EOF */
|
||||
if (offset < 0 || data->physical_offset >= data->stream_offset + data->stream_size) {
|
||||
break;
|
||||
}
|
||||
|
||||
length_available = (streamfile->current_logical_offset + streamfile->current_block_size) - offset;
|
||||
/* process new block */
|
||||
if (data->data_size == 0) {
|
||||
uint32_t block_id = read_u32be(data->physical_offset+0x00, streamfile);
|
||||
data->block_size = read_u32be(data->physical_offset+0x04, streamfile) + 0x08;
|
||||
|
||||
if (length < length_available) {
|
||||
to_read = length;
|
||||
}
|
||||
else {
|
||||
to_read = length_available;
|
||||
/* check valid block "AIXP" id, knowing that AIX segments end with "AIXE" block too */
|
||||
if (block_id != 0x41495850 || data->block_size == 0 || data->block_size == 0xFFFFFFFF) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (to_read > 0) {
|
||||
size_t bytes_read;
|
||||
|
||||
bytes_read = read_streamfile(dest,
|
||||
streamfile->current_physical_offset+0x10 + (offset-streamfile->current_logical_offset),
|
||||
to_read,streamfile->real_file);
|
||||
|
||||
sz += bytes_read;
|
||||
if (bytes_read != to_read) {
|
||||
return sz; /* an error which we will not attempt to handle here */
|
||||
}
|
||||
|
||||
read_something = 1;
|
||||
|
||||
dest += bytes_read;
|
||||
offset += bytes_read;
|
||||
length -= bytes_read;
|
||||
/* read target layer, otherwise skip to next block and try again */
|
||||
if (read_s8(data->physical_offset+0x08, streamfile) == data->layer_number) {
|
||||
/* 0x09(1): layer count */
|
||||
data->data_size = read_s16be(data->physical_offset+0x0a, streamfile);
|
||||
/* 0x0c: -1 */
|
||||
data->skip_size = 0x10;
|
||||
}
|
||||
}
|
||||
|
||||
if (!read_something) {
|
||||
/* couldn't read anything, must seek */
|
||||
int found_block = 0;
|
||||
/* 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;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* as we have no memory we must start seeking from the beginning */
|
||||
if (offset < streamfile->current_logical_offset) {
|
||||
streamfile->current_logical_offset = 0;
|
||||
streamfile->current_block_size = 0;
|
||||
streamfile->current_physical_offset = streamfile->start_physical_offset;
|
||||
/* read 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, streamfile);
|
||||
|
||||
total_read += bytes_done;
|
||||
dest += bytes_done;
|
||||
offset += bytes_done;
|
||||
length -= bytes_done;
|
||||
|
||||
if (bytes_done != to_read || bytes_done == 0) {
|
||||
break; /* error/EOF */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* seek ye forwards */
|
||||
while (!found_block) {
|
||||
/*printf("seek looks at %x\n",streamfile->current_physical_offset);*/
|
||||
switch (read_32bitBE(streamfile->current_physical_offset, streamfile->real_file)) {
|
||||
case 0x41495850: /* AIXP */
|
||||
if (read_8bit(streamfile->current_physical_offset+8, streamfile->real_file) == streamfile->stream_id) {
|
||||
streamfile->current_block_size = (uint16_t)read_16bitBE(streamfile->current_physical_offset+0x0a, streamfile->real_file);
|
||||
|
||||
if (offset >= streamfile->current_logical_offset+ streamfile->current_block_size) {
|
||||
streamfile->current_logical_offset += streamfile->current_block_size;
|
||||
}
|
||||
else {
|
||||
found_block = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_block) {
|
||||
streamfile->current_physical_offset += read_32bitBE(streamfile->current_physical_offset+0x04, streamfile->real_file) + 8;
|
||||
}
|
||||
|
||||
break;
|
||||
case 0x41495846: /* AIXF */
|
||||
/* shouldn't ever see this */
|
||||
case 0x41495845: /* AIXE */
|
||||
/* shouldn't have reached the end o' the line... */
|
||||
default:
|
||||
return sz;
|
||||
break;
|
||||
} /* end block/chunk type select */
|
||||
} /* end while !found_block */
|
||||
} /* end if !read_something */
|
||||
} /* end while length > 0 */
|
||||
|
||||
return sz;
|
||||
return total_read;
|
||||
}
|
||||
|
||||
static void close_aix(AIXSTREAMFILE *streamfile) {
|
||||
free(streamfile);
|
||||
return;
|
||||
static size_t aix_io_size(STREAMFILE *streamfile, aix_io_data* data) {
|
||||
uint8_t buf[1];
|
||||
|
||||
if (data->logical_size)
|
||||
return data->logical_size;
|
||||
|
||||
/* force a fake read at max offset, to get max logical_offset (will be reset next read) */
|
||||
aix_io_read(streamfile, buf, 0x7FFFFFFF, 1, data);
|
||||
data->logical_size = data->logical_offset;
|
||||
|
||||
return data->logical_size;
|
||||
}
|
||||
|
||||
static size_t get_size_aix(AIXSTREAMFILE *streamfile) {
|
||||
return 0;
|
||||
}
|
||||
/* Handles deinterleaving of AIX blocked layer streams */
|
||||
static STREAMFILE* setup_aix_streamfile(STREAMFILE *streamFile, off_t stream_offset, size_t stream_size, int layer_number, const char* extension) {
|
||||
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
|
||||
aix_io_data io_data = {0};
|
||||
size_t io_data_size = sizeof(aix_io_data);
|
||||
|
||||
static size_t get_offset_aix(AIXSTREAMFILE *streamfile) {
|
||||
return streamfile->current_logical_offset;
|
||||
}
|
||||
io_data.stream_offset = stream_offset;
|
||||
io_data.stream_size = stream_size;
|
||||
io_data.layer_number = layer_number;
|
||||
io_data.logical_offset = -1; /* force reset */
|
||||
|
||||
static void get_name_aix(AIXSTREAMFILE *streamfile,char *buffer,size_t length) {
|
||||
strncpy(buffer,"ARBITRARY.ADX",length);
|
||||
buffer[length-1]='\0';
|
||||
}
|
||||
/* setup subfile */
|
||||
new_streamFile = open_wrap_streamfile(streamFile);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
static STREAMFILE *open_aix_impl(AIXSTREAMFILE *streamfile,const char * const filename,size_t buffersize) {
|
||||
AIXSTREAMFILE *newfile;
|
||||
if (strcmp(filename,"ARBITRARY.ADX"))
|
||||
return NULL;
|
||||
new_streamFile = open_io_streamfile(new_streamFile, &io_data,io_data_size, aix_io_read,aix_io_size);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
newfile = malloc(sizeof(AIXSTREAMFILE));
|
||||
if (!newfile)
|
||||
return NULL;
|
||||
memcpy(newfile,streamfile,sizeof(AIXSTREAMFILE));
|
||||
return &newfile->sf;
|
||||
}
|
||||
new_streamFile = open_buffer_streamfile(new_streamFile,0);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
/*static*/ STREAMFILE *open_aix_with_STREAMFILE(STREAMFILE *file, off_t start_offset, int stream_id) {
|
||||
AIXSTREAMFILE *streamfile = malloc(sizeof(AIXSTREAMFILE));
|
||||
if (extension) {
|
||||
new_streamFile = open_fakename_streamfile(temp_streamFile, NULL,extension);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
}
|
||||
|
||||
if (!streamfile)
|
||||
return NULL;
|
||||
return temp_streamFile;
|
||||
|
||||
/* success, set our pointers */
|
||||
|
||||
streamfile->sf.read = (void*)read_aix;
|
||||
streamfile->sf.get_size = (void*)get_size_aix;
|
||||
streamfile->sf.get_offset = (void*)get_offset_aix;
|
||||
streamfile->sf.get_name = (void*)get_name_aix;
|
||||
streamfile->sf.open = (void*)open_aix_impl;
|
||||
streamfile->sf.close = (void*)close_aix;
|
||||
|
||||
streamfile->real_file = file;
|
||||
streamfile->current_physical_offset = start_offset;
|
||||
streamfile->start_physical_offset = start_offset;
|
||||
streamfile->current_logical_offset = 0;
|
||||
streamfile->current_block_size = 0;
|
||||
streamfile->stream_id = stream_id;
|
||||
|
||||
return &streamfile->sf;
|
||||
fail:
|
||||
close_streamfile(temp_streamFile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* _AIX_STREAMFILE_H_ */
|
||||
|
Loading…
x
Reference in New Issue
Block a user