mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-01-05 18:04:25 +01:00
5672cac597
The code may be standardized and extended in the future for some meta needing similar features, so this is just to signal its existence
135 lines
4.1 KiB
C
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_ */
|