vgmstream/src/meta/sqex_scd_streamfile.h
bnnm 5672cac597 Move some meta STREAMFILEs to separate file for visibility
The code may be standardized and extended in the future for some meta
needing similar features, so this is just to signal its existence
2017-12-06 12:15:27 +01:00

135 lines
4.1 KiB
C

#ifndef _SQEX_SCD_STREAMFILE_H_
#define _SQEX_SCD_STREAMFILE_H_
#include "../streamfile.h"
/* special streamfile type to handle deinterleaving of complete files (based heavily on AIXSTREAMFILE */
typedef struct _SCDINTSTREAMFILE {
STREAMFILE sf;
STREAMFILE *real_file;
const char * filename;
off_t start_physical_offset;
off_t current_logical_offset;
off_t interleave_block_size;
off_t stride_size;
size_t total_size;
} SCDINTSTREAMFILE;
/*static*/ STREAMFILE *open_scdint_with_STREAMFILE(STREAMFILE *file, const char * filename, off_t start_offset, off_t interleave_block_size, off_t stride_size, size_t total_size);
static STREAMFILE *open_scdint_impl(SCDINTSTREAMFILE *streamfile,const char * const filename,size_t buffersize) {
SCDINTSTREAMFILE *newfile;
if (strcmp(filename, streamfile->filename))
return NULL;
newfile = malloc(sizeof(SCDINTSTREAMFILE));
if (!newfile)
return NULL;
memcpy(newfile,streamfile,sizeof(SCDINTSTREAMFILE));
return &newfile->sf;
}
static void close_scdint(SCDINTSTREAMFILE *streamfile) {
free(streamfile);
return;
}
static size_t get_size_scdint(SCDINTSTREAMFILE *streamfile) {
return streamfile->total_size;
}
static size_t get_offset_scdint(SCDINTSTREAMFILE *streamfile) {
return streamfile->current_logical_offset;
}
static void get_name_scdint(SCDINTSTREAMFILE *streamfile, char *buffer, size_t length) {
strncpy(buffer,streamfile->filename,length);
buffer[length-1]='\0';
}
static size_t read_scdint(SCDINTSTREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length) {
size_t sz = 0;
while (length > 0) {
off_t to_read;
off_t length_available;
off_t block_num;
off_t intrablock_offset;
off_t physical_offset;
block_num = offset / streamfile->interleave_block_size;
intrablock_offset = offset % streamfile->interleave_block_size;
streamfile->current_logical_offset = offset;
physical_offset = streamfile->start_physical_offset + block_num * streamfile->stride_size + intrablock_offset;
length_available = streamfile->interleave_block_size - intrablock_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,
physical_offset,
to_read, streamfile->real_file);
sz += bytes_read;
streamfile->current_logical_offset = offset + bytes_read;
if (bytes_read != to_read) {
return sz; /* an error which we will not attempt to handle here */
}
dest += bytes_read;
offset += bytes_read;
length -= bytes_read;
}
}
return sz;
}
/* start_offset is for *this* interleaved stream */
/*static*/ STREAMFILE *open_scdint_with_STREAMFILE(STREAMFILE *file, const char * filename, off_t start_offset, off_t interleave_block_size, off_t stride_size, size_t total_size) {
SCDINTSTREAMFILE * scd = NULL;
/* _scdint funcs can't handle this case */
if (start_offset + total_size > file->get_size(file))
return NULL;
scd = malloc(sizeof(SCDINTSTREAMFILE));
if (!scd)
return NULL;
scd->sf.read = (void*)read_scdint;
scd->sf.get_size = (void*)get_size_scdint;
scd->sf.get_offset = (void*)get_offset_scdint;
scd->sf.get_name = (void*)get_name_scdint;
scd->sf.get_realname = (void*)get_name_scdint;
scd->sf.open = (void*)open_scdint_impl;
scd->sf.close = (void*)close_scdint;
scd->real_file = file;
scd->filename = filename;
scd->start_physical_offset = start_offset;
scd->current_logical_offset = 0;
scd->interleave_block_size = interleave_block_size;
scd->stride_size = stride_size;
scd->total_size = total_size;
return &scd->sf;
}
#endif /* _SCD_STREAMFILE_H_ */