vgmstream/src/meta/aix.c

246 lines
7.3 KiB
C
Raw Normal View History

#include "../vgmstream.h"
#include "meta.h"
#include "../util.h"
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;
VGMSTREAM * init_vgmstream_aix(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
STREAMFILE * streamFileADX = NULL;
char filename[260];
int i;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("aix",filename_extension(filename))) goto fail;
streamFileADX = streamFile->open(streamFile,filenameWAV,STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!streamFileWAV) {
/* try again, ucase */
for (i=strlen(filenameWAV);i>=0&&filenameWAV[i]!=DIRSEP;i--)
filenameWAV[i]=toupper(filenameWAV[i]);
streamFileWAV = streamFile->open(streamFile,filenameWAV,STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!streamFileWAV) goto fail;
}
/* let the real initer do the parsing */
vgmstream = init_vgmstream_riff(streamFileWAV);
if (!vgmstream) goto fail;
close_streamfile(streamFileWAV);
streamFileWAV = NULL;
/* install loops */
if (!vgmstream->loop_flag) {
vgmstream->loop_flag = 1;
vgmstream->loop_ch = calloc(vgmstream->channels,
sizeof(VGMSTREAMCHANNEL));
if (!vgmstream->loop_ch) goto fail;
}
vgmstream->loop_start_sample = read_32bitLE(0,streamFile);
vgmstream->loop_end_sample = read_32bitLE(4,streamFile);
vgmstream->meta_type = meta_RIFF_WAVE_POS;
return vgmstream;
/* clean up anything we may have opened */
fail:
if (streamFileWAV) close_streamfile(streamFileWAV);
if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}
static size_t read_aix(AIXSTREAMFILE *streamfile,uint8_t *dest,off_t offset,size_t length)
{
size_t sz = 0;
while (length > 0)
{
int read_something = 0;
if (offset >= logical_file_size)
{
return sz;
}
/* read the beginning of the requested block, if we can */
if (offset >= streamfile->current_logical_offset)
{
off_t to_read;
off_t length_available;
length_available =
(streamfile->current_logical_offset+
streamfile->current_block_size) -
offset;
if (length < length_available)
{
to_read = length;
}
else
{
to_read = length_available;
}
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)
{
/* an error which we will not attempt to handle here */
return sz;
}
read_something = 1;
dest += bytes_read;
offset += bytes_read;
length -= bytes_read;
}
}
if (!read_something)
{
/* couldn't read anything, must seek */
int found_block = 0;
/* 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;
}
/* seek ye forwards */
while (!found_block) {
switch (read_32bitBE(streamfile->current_physical_offset,
streamfile->real_file))
{
case 0x41495850: /* AIXP */
if (read_8bitBE(
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;
streamfile->current_physical_offset +=
read_32bitBE(
streamfile->current_physical_offset+0x04,
streamfile->real_file
);
}
}
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;
}
static void close_aix(AIXSTREAMFILE *streamfile)
{
free(streamfile);
return;
}
static size_t get_size_aix(AIXSTREAMFILE *streamfile)
{
return 0;
}
static size_t get_offset_aix(AIXSTREAMFILE *streamfile)
{
return streamfile->current_logical_offset;
}
static void get_name_aix(AIXSTREAMFILE *streamfile,char *buffer,size_t length)
{
strncpy(buffer,length,"ARBITRARY.ADX");
buffer[length-1]='\0';
}
static STREAMFILE *open_aix_impl(AIXSTREAMFILE *streamfile,const char * const filename,size_t buffersize)
{
AIXSTREAMFILE *newfile;
if (strcmp(filename,"ARBITRARY.ADX"))
return NULL;
newfile = malloc(sizeof(AIXSTREAMFILE));
if (!newfile)
return NULL;
memcpy(newfile,streamfile,sizeof(AIXSTREAMFILE));
return newfile;
}
static STREAMFILE *open_aix_with_STREAMFILE(STREAMFILE *file,off_t start_offset,int stream_id);
{
AIXSTREAMFILE *streamfile = malloc(sizeof(AIXSTREAMFILE));
if (!streamfile)
return NULL;
/* 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.get_realname = (void*)get_name_aix;
streamfile->sf.open = (void*)open_aix_impl;
streamfile->sf.close = (void*)close_aix;
#ifdef PROFILE_STREAMFILE
streamfile->sf.get_bytes_read = NULL;
streamfile->sf.get_error_count = NULL;
#endif
streamfile->real_file = file;
streamfile->current_physicial_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;
}