mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-24 15:00:11 +01:00
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
This commit is contained in:
parent
c8cc25c84b
commit
5672cac597
109
src/meta/aax.c
109
src/meta/aax.c
@ -1,16 +1,5 @@
|
|||||||
#include "../vgmstream.h"
|
|
||||||
#include "meta.h"
|
#include "meta.h"
|
||||||
#include "../util.h"
|
#include "aax_streamfile.h"
|
||||||
|
|
||||||
typedef struct _AAXSTREAMFILE
|
|
||||||
{
|
|
||||||
STREAMFILE sf;
|
|
||||||
STREAMFILE *real_file;
|
|
||||||
off_t start_physical_offset;
|
|
||||||
size_t file_size;
|
|
||||||
} AAXSTREAMFILE;
|
|
||||||
|
|
||||||
static STREAMFILE *open_aax_with_STREAMFILE(STREAMFILE *file,off_t start_offset,size_t file_size);
|
|
||||||
|
|
||||||
struct utf_query
|
struct utf_query
|
||||||
{
|
{
|
||||||
@ -107,10 +96,9 @@ struct utf_table_info
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* Actual AAX init fcn */
|
/* AAX - segmented ADX [Padora's Tower (Wii)] */
|
||||||
VGMSTREAM * init_vgmstream_aax(STREAMFILE *streamFile) {
|
VGMSTREAM * init_vgmstream_aax(STREAMFILE *streamFile) {
|
||||||
|
VGMSTREAM * vgmstream = NULL;
|
||||||
VGMSTREAM * vgmstream = NULL;
|
|
||||||
STREAMFILE * streamFileAAX = NULL;
|
STREAMFILE * streamFileAAX = NULL;
|
||||||
STREAMFILE * streamFileADX = NULL;
|
STREAMFILE * streamFileADX = NULL;
|
||||||
char filename[PATH_LIMIT];
|
char filename[PATH_LIMIT];
|
||||||
@ -131,7 +119,7 @@ VGMSTREAM * init_vgmstream_aax(STREAMFILE *streamFile) {
|
|||||||
int channel_count = 0, segment_count;
|
int channel_count = 0, segment_count;
|
||||||
int sample_rate = 0;
|
int sample_rate = 0;
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
|
||||||
long aax_data_offset;
|
long aax_data_offset;
|
||||||
@ -297,91 +285,6 @@ fail:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* virtual file, a piece of the overall file */
|
|
||||||
|
|
||||||
static size_t read_aax(AAXSTREAMFILE *streamfile,uint8_t *dest,off_t offset,size_t length)
|
|
||||||
{
|
|
||||||
/* truncate at end of logical file */
|
|
||||||
if (offset+length > streamfile->file_size)
|
|
||||||
{
|
|
||||||
long signed_length = length;
|
|
||||||
signed_length = streamfile->file_size - offset;
|
|
||||||
if (signed_length < 0) signed_length = 0;
|
|
||||||
length = signed_length;
|
|
||||||
}
|
|
||||||
return read_streamfile(dest,
|
|
||||||
streamfile->start_physical_offset+offset,
|
|
||||||
length,streamfile->real_file);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void close_aax(AAXSTREAMFILE *streamfile)
|
|
||||||
{
|
|
||||||
free(streamfile);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t get_size_aax(AAXSTREAMFILE *streamfile)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t get_offset_aax(AAXSTREAMFILE *streamfile)
|
|
||||||
{
|
|
||||||
long offset = streamfile->real_file->get_offset(streamfile->real_file);
|
|
||||||
offset -= streamfile->start_physical_offset;
|
|
||||||
if (offset < 0) offset = 0;
|
|
||||||
if (offset > streamfile->file_size) offset = streamfile->file_size;
|
|
||||||
|
|
||||||
return offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void get_name_aax(AAXSTREAMFILE *streamfile,char *buffer,size_t length)
|
|
||||||
{
|
|
||||||
strncpy(buffer,"ARBITRARY.ADX",length);
|
|
||||||
buffer[length-1]='\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
static STREAMFILE *open_aax_impl(AAXSTREAMFILE *streamfile,const char * const filename,size_t buffersize)
|
|
||||||
{
|
|
||||||
AAXSTREAMFILE *newfile;
|
|
||||||
if (strcmp(filename,"ARBITRARY.ADX"))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
newfile = malloc(sizeof(AAXSTREAMFILE));
|
|
||||||
if (!newfile)
|
|
||||||
return NULL;
|
|
||||||
memcpy(newfile,streamfile,sizeof(AAXSTREAMFILE));
|
|
||||||
return &newfile->sf;
|
|
||||||
}
|
|
||||||
|
|
||||||
static STREAMFILE *open_aax_with_STREAMFILE(STREAMFILE *file,off_t start_offset,size_t file_size)
|
|
||||||
{
|
|
||||||
AAXSTREAMFILE *streamfile = malloc(sizeof(AAXSTREAMFILE));
|
|
||||||
|
|
||||||
if (!streamfile)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/* success, set our pointers */
|
|
||||||
|
|
||||||
streamfile->sf.read = (void*)read_aax;
|
|
||||||
streamfile->sf.get_size = (void*)get_size_aax;
|
|
||||||
streamfile->sf.get_offset = (void*)get_offset_aax;
|
|
||||||
streamfile->sf.get_name = (void*)get_name_aax;
|
|
||||||
streamfile->sf.get_realname = (void*)get_name_aax;
|
|
||||||
streamfile->sf.open = (void*)open_aax_impl;
|
|
||||||
streamfile->sf.close = (void*)close_aax;
|
|
||||||
#ifdef PROFILE_STREAMFILE
|
|
||||||
streamfile->sf.get_bytes_read = NULL;
|
|
||||||
streamfile->sf.get_error_count = NULL;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
streamfile->real_file = file;
|
|
||||||
streamfile->start_physical_offset = start_offset;
|
|
||||||
streamfile->file_size = file_size;
|
|
||||||
|
|
||||||
return &streamfile->sf;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* @UTF table reading, abridged */
|
/* @UTF table reading, abridged */
|
||||||
static struct utf_query_result analyze_utf(STREAMFILE *infile, const long offset, const struct utf_query *query)
|
static struct utf_query_result analyze_utf(STREAMFILE *infile, const long offset, const struct utf_query *query)
|
||||||
{
|
{
|
||||||
@ -744,8 +647,7 @@ static struct offset_size_pair query_utf_data(STREAMFILE *infile, const long off
|
|||||||
|
|
||||||
/* CRI's UTF wrapper around DSP */
|
/* CRI's UTF wrapper around DSP */
|
||||||
VGMSTREAM * init_vgmstream_utf_dsp(STREAMFILE *streamFile) {
|
VGMSTREAM * init_vgmstream_utf_dsp(STREAMFILE *streamFile) {
|
||||||
|
VGMSTREAM * vgmstream = NULL;
|
||||||
VGMSTREAM * vgmstream = NULL;
|
|
||||||
char filename[PATH_LIMIT];
|
char filename[PATH_LIMIT];
|
||||||
int table_error = 0;
|
int table_error = 0;
|
||||||
|
|
||||||
@ -843,4 +745,3 @@ fail:
|
|||||||
if (vgmstream) close_vgmstream(vgmstream);
|
if (vgmstream) close_vgmstream(vgmstream);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
87
src/meta/aax_streamfile.h
Normal file
87
src/meta/aax_streamfile.h
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
#ifndef _AAX_STREAMFILE_H_
|
||||||
|
#define _AAX_STREAMFILE_H_
|
||||||
|
#include "../streamfile.h"
|
||||||
|
|
||||||
|
/* a streamfile representing a subfile inside another */
|
||||||
|
|
||||||
|
typedef struct _AAXSTREAMFILE {
|
||||||
|
STREAMFILE sf;
|
||||||
|
STREAMFILE *real_file;
|
||||||
|
off_t start_physical_offset;
|
||||||
|
size_t file_size;
|
||||||
|
} AAXSTREAMFILE;
|
||||||
|
|
||||||
|
static size_t read_aax(AAXSTREAMFILE *streamfile,uint8_t *dest,off_t offset,size_t length) {
|
||||||
|
/* truncate at end of logical file */
|
||||||
|
if (offset+length > streamfile->file_size) {
|
||||||
|
long signed_length = length;
|
||||||
|
signed_length = streamfile->file_size - offset;
|
||||||
|
if (signed_length < 0) signed_length = 0;
|
||||||
|
length = signed_length;
|
||||||
|
}
|
||||||
|
return read_streamfile(dest, streamfile->start_physical_offset+offset, length,streamfile->real_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void close_aax(AAXSTREAMFILE *streamfile) {
|
||||||
|
free(streamfile);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t get_size_aax(AAXSTREAMFILE *streamfile) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t get_offset_aax(AAXSTREAMFILE *streamfile) {
|
||||||
|
long offset = streamfile->real_file->get_offset(streamfile->real_file);
|
||||||
|
offset -= streamfile->start_physical_offset;
|
||||||
|
if (offset < 0) offset = 0;
|
||||||
|
if (offset > streamfile->file_size) offset = streamfile->file_size;
|
||||||
|
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void get_name_aax(AAXSTREAMFILE *streamfile,char *buffer,size_t length) {
|
||||||
|
strncpy(buffer,"ARBITRARY.ADX",length);
|
||||||
|
buffer[length-1]='\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
static STREAMFILE *open_aax_impl(AAXSTREAMFILE *streamfile,const char * const filename,size_t buffersize) {
|
||||||
|
AAXSTREAMFILE *newfile;
|
||||||
|
if (strcmp(filename,"ARBITRARY.ADX"))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
newfile = malloc(sizeof(AAXSTREAMFILE));
|
||||||
|
if (!newfile)
|
||||||
|
return NULL;
|
||||||
|
memcpy(newfile,streamfile,sizeof(AAXSTREAMFILE));
|
||||||
|
return &newfile->sf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static STREAMFILE *open_aax_with_STREAMFILE(STREAMFILE *file,off_t start_offset,size_t file_size) {
|
||||||
|
AAXSTREAMFILE *streamfile = malloc(sizeof(AAXSTREAMFILE));
|
||||||
|
|
||||||
|
if (!streamfile)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* success, set our pointers */
|
||||||
|
|
||||||
|
streamfile->sf.read = (void*)read_aax;
|
||||||
|
streamfile->sf.get_size = (void*)get_size_aax;
|
||||||
|
streamfile->sf.get_offset = (void*)get_offset_aax;
|
||||||
|
streamfile->sf.get_name = (void*)get_name_aax;
|
||||||
|
streamfile->sf.get_realname = (void*)get_name_aax;
|
||||||
|
streamfile->sf.open = (void*)open_aax_impl;
|
||||||
|
streamfile->sf.close = (void*)close_aax;
|
||||||
|
#ifdef PROFILE_STREAMFILE
|
||||||
|
streamfile->sf.get_bytes_read = NULL;
|
||||||
|
streamfile->sf.get_error_count = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
streamfile->real_file = file;
|
||||||
|
streamfile->start_physical_offset = start_offset;
|
||||||
|
streamfile->file_size = file_size;
|
||||||
|
|
||||||
|
return &streamfile->sf;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _AAX_STREAMFILE_H_ */
|
204
src/meta/aix.c
204
src/meta/aix.c
@ -1,20 +1,7 @@
|
|||||||
#include "../vgmstream.h"
|
|
||||||
#include "meta.h"
|
#include "meta.h"
|
||||||
#include "../util.h"
|
#include "aix_streamfile.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;
|
|
||||||
|
|
||||||
static STREAMFILE *open_aix_with_STREAMFILE(STREAMFILE *file,off_t start_offset,int stream_id);
|
|
||||||
|
|
||||||
|
/* AIX - interleaved AAX, N segments per channels [SoulCalibur IV (PS3)] */
|
||||||
VGMSTREAM * init_vgmstream_aix(STREAMFILE *streamFile) {
|
VGMSTREAM * init_vgmstream_aix(STREAMFILE *streamFile) {
|
||||||
|
|
||||||
VGMSTREAM * vgmstream = NULL;
|
VGMSTREAM * vgmstream = NULL;
|
||||||
@ -228,190 +215,3 @@ fail:
|
|||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
static size_t read_aix(AIXSTREAMFILE *streamfile,uint8_t *dest,off_t offset,size_t length)
|
|
||||||
{
|
|
||||||
size_t sz = 0;
|
|
||||||
|
|
||||||
/*printf("trying to read %x bytes from %x (str%d)\n",length,offset,streamfile->stream_id);*/
|
|
||||||
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;
|
|
||||||
|
|
||||||
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) {
|
|
||||||
/*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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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,"ARBITRARY.ADX",length);
|
|
||||||
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->sf;
|
|
||||||
}
|
|
||||||
|
|
||||||
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_physical_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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
169
src/meta/aix_streamfile.h
Normal file
169
src/meta/aix_streamfile.h
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
#ifndef _AIX_STREAMFILE_H_
|
||||||
|
#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;
|
||||||
|
|
||||||
|
|
||||||
|
/*static*/ STREAMFILE *open_aix_with_STREAMFILE(STREAMFILE *file, off_t start_offset, int stream_id);
|
||||||
|
|
||||||
|
|
||||||
|
static size_t read_aix(AIXSTREAMFILE *streamfile,uint8_t *dest,off_t offset,size_t length) {
|
||||||
|
size_t sz = 0;
|
||||||
|
|
||||||
|
/*printf("trying to read %x bytes from %x (str%d)\n",length,offset,streamfile->stream_id);*/
|
||||||
|
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;
|
||||||
|
|
||||||
|
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) {
|
||||||
|
return sz; /* an error which we will not attempt to handle here */
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
/*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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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,"ARBITRARY.ADX",length);
|
||||||
|
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->sf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*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_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _AIX_STREAMFILE_H_ */
|
@ -1,26 +1,10 @@
|
|||||||
#include "meta.h"
|
#include "meta.h"
|
||||||
|
#include "gh3_bar_streamfile.h"
|
||||||
|
|
||||||
// Guitar Hero III Mobile .bar
|
/* Guitar Hero III Mobile .bar */
|
||||||
|
|
||||||
enum {BAR_KEY_LENGTH = 16};
|
|
||||||
|
|
||||||
// don't know if this is unique, but seems accurate
|
|
||||||
static const uint8_t bar_key[BAR_KEY_LENGTH] =
|
|
||||||
{0xbd,0x14,0x0e,0x0a,0x91,0xeb,0xaa,0xf6,
|
|
||||||
0x11,0x44,0x17,0xc2,0x1c,0xe4,0x66,0x80};
|
|
||||||
|
|
||||||
typedef struct _BARSTREAM
|
|
||||||
{
|
|
||||||
STREAMFILE sf;
|
|
||||||
STREAMFILE *real_file;
|
|
||||||
} BARSTREAM;
|
|
||||||
|
|
||||||
STREAMFILE *wrap_bar_STREAMFILE(STREAMFILE *file);
|
|
||||||
|
|
||||||
VGMSTREAM * init_vgmstream_gh3_bar(STREAMFILE *streamFile) {
|
VGMSTREAM * init_vgmstream_gh3_bar(STREAMFILE *streamFile) {
|
||||||
VGMSTREAM * vgmstream = NULL;
|
VGMSTREAM * vgmstream = NULL;
|
||||||
// don't close, this is just the source streamFile wrapped
|
STREAMFILE* streamFileBAR = NULL; // don't close, this is just the source streamFile wrapped
|
||||||
STREAMFILE* streamFileBAR = NULL;
|
|
||||||
char filename[PATH_LIMIT];
|
char filename[PATH_LIMIT];
|
||||||
off_t start_offset;
|
off_t start_offset;
|
||||||
off_t ch2_start_offset;
|
off_t ch2_start_offset;
|
||||||
@ -91,92 +75,3 @@ fail:
|
|||||||
if (vgmstream) close_vgmstream(vgmstream);
|
if (vgmstream) close_vgmstream(vgmstream);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t read_bar(BARSTREAM *streamFile, uint8_t *dest, off_t offset, size_t length)
|
|
||||||
{
|
|
||||||
off_t i;
|
|
||||||
size_t read_length =
|
|
||||||
streamFile->real_file->read(streamFile->real_file, dest, offset, length);
|
|
||||||
|
|
||||||
for (i = 0; i < read_length; i++)
|
|
||||||
{
|
|
||||||
dest[i] = dest[i] ^ bar_key[(i+offset)%BAR_KEY_LENGTH];
|
|
||||||
}
|
|
||||||
|
|
||||||
return read_length;
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t get_size_bar(BARSTREAM *streamFile)
|
|
||||||
{
|
|
||||||
return streamFile->real_file->get_size(streamFile->real_file);
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t get_offset_bar(BARSTREAM *streamFile)
|
|
||||||
{
|
|
||||||
return streamFile->real_file->get_offset(streamFile->real_file);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void get_name_bar(BARSTREAM *streamFile, char *name, size_t length)
|
|
||||||
{
|
|
||||||
return streamFile->real_file->get_name(streamFile->real_file, name, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void get_realname_bar(BARSTREAM *streamFile, char *name, size_t length)
|
|
||||||
{
|
|
||||||
return streamFile->real_file->get_realname(streamFile->real_file, name, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
STREAMFILE *open_bar(BARSTREAM *streamFile, const char * const filename, size_t buffersize)
|
|
||||||
{
|
|
||||||
STREAMFILE *newfile = streamFile->real_file->open(
|
|
||||||
streamFile->real_file,filename,buffersize);
|
|
||||||
if (!newfile)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
return wrap_bar_STREAMFILE(newfile);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void close_bar(BARSTREAM *streamFile)
|
|
||||||
{
|
|
||||||
streamFile->real_file->close(streamFile->real_file);
|
|
||||||
free(streamFile);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef PROFILE_STREAMFILE
|
|
||||||
size_t get_bytes_read_bar(BARSTREAM *streamFile)
|
|
||||||
{
|
|
||||||
return streamFile->real_file->get_bytes_read(streamFile->real_file);
|
|
||||||
}
|
|
||||||
|
|
||||||
int (*get_error_count)(BARSTREAM *streamFile)
|
|
||||||
{
|
|
||||||
return streamFile->real_file->get_error_count(streamFile->real_file);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
STREAMFILE *wrap_bar_STREAMFILE(STREAMFILE *file)
|
|
||||||
{
|
|
||||||
BARSTREAM *streamfile = malloc(sizeof(BARSTREAM));
|
|
||||||
|
|
||||||
if (!streamfile)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
memset(streamfile, 0, sizeof(BARSTREAM));
|
|
||||||
|
|
||||||
streamfile->sf.read = (void*)read_bar;
|
|
||||||
streamfile->sf.get_size = (void*)get_size_bar;
|
|
||||||
streamfile->sf.get_offset = (void*)get_offset_bar;
|
|
||||||
streamfile->sf.get_name = (void*)get_name_bar;
|
|
||||||
streamfile->sf.get_realname = (void*)get_realname_bar;
|
|
||||||
streamfile->sf.open = (void*)open_bar;
|
|
||||||
streamfile->sf.close = (void*)close_bar;
|
|
||||||
#ifdef PROFILE_STREAMFILE
|
|
||||||
streamfile->sf.get_bytes_read = get_bytes_read_bar;
|
|
||||||
streamfile->sf.get_error_count = get_error_count_bar;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
streamfile->real_file = file;
|
|
||||||
|
|
||||||
return &streamfile->sf;
|
|
||||||
}
|
|
||||||
|
100
src/meta/gh3_bar_streamfile.h
Normal file
100
src/meta/gh3_bar_streamfile.h
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
#ifndef _GH3_BAR_STREAMFILE_H_
|
||||||
|
#define _GH3_BAR_STREAMFILE_H_
|
||||||
|
#include "../streamfile.h"
|
||||||
|
|
||||||
|
/* a streamfile wrapping another for decryption */
|
||||||
|
|
||||||
|
enum {BAR_KEY_LENGTH = 16};
|
||||||
|
|
||||||
|
// don't know if this is unique, but seems accurate
|
||||||
|
static const uint8_t bar_key[BAR_KEY_LENGTH] = {
|
||||||
|
0xbd,0x14,0x0e,0x0a,0x91,0xeb,0xaa,0xf6,
|
||||||
|
0x11,0x44,0x17,0xc2,0x1c,0xe4,0x66,0x80
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct _BARSTREAMFILE {
|
||||||
|
STREAMFILE sf;
|
||||||
|
STREAMFILE *real_file;
|
||||||
|
} BARSTREAMFILE;
|
||||||
|
|
||||||
|
|
||||||
|
/*static*/ STREAMFILE *wrap_bar_STREAMFILE(STREAMFILE *file);
|
||||||
|
|
||||||
|
|
||||||
|
static size_t read_bar(BARSTREAMFILE *streamFile, uint8_t *dest, off_t offset, size_t length) {
|
||||||
|
off_t i;
|
||||||
|
size_t read_length = streamFile->real_file->read(streamFile->real_file, dest, offset, length);
|
||||||
|
|
||||||
|
for (i = 0; i < read_length; i++) {
|
||||||
|
dest[i] = dest[i] ^ bar_key[(i+offset)%BAR_KEY_LENGTH];
|
||||||
|
}
|
||||||
|
|
||||||
|
return read_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t get_size_bar(BARSTREAMFILE *streamFile) {
|
||||||
|
return streamFile->real_file->get_size(streamFile->real_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t get_offset_bar(BARSTREAMFILE *streamFile) {
|
||||||
|
return streamFile->real_file->get_offset(streamFile->real_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void get_name_bar(BARSTREAMFILE *streamFile, char *name, size_t length) {
|
||||||
|
return streamFile->real_file->get_name(streamFile->real_file, name, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void get_realname_bar(BARSTREAMFILE *streamFile, char *name, size_t length) {
|
||||||
|
return streamFile->real_file->get_realname(streamFile->real_file, name, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
STREAMFILE *open_bar(BARSTREAMFILE *streamFile, const char * const filename, size_t buffersize) {
|
||||||
|
STREAMFILE *newfile = streamFile->real_file->open(streamFile->real_file,filename,buffersize);
|
||||||
|
if (!newfile)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return wrap_bar_STREAMFILE(newfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void close_bar(BARSTREAMFILE *streamFile) {
|
||||||
|
streamFile->real_file->close(streamFile->real_file);
|
||||||
|
free(streamFile);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef PROFILE_STREAMFILE
|
||||||
|
size_t get_bytes_read_bar(BARSTREAMFILE *streamFile) {
|
||||||
|
return streamFile->real_file->get_bytes_read(streamFile->real_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
int (*get_error_count)(BARSTREAMFILE *streamFile) {
|
||||||
|
return streamFile->real_file->get_error_count(streamFile->real_file);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*static*/ STREAMFILE *wrap_bar_STREAMFILE(STREAMFILE *file) {
|
||||||
|
BARSTREAMFILE *streamfile = malloc(sizeof(BARSTREAMFILE));
|
||||||
|
|
||||||
|
if (!streamfile)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
memset(streamfile, 0, sizeof(BARSTREAMFILE));
|
||||||
|
|
||||||
|
streamfile->sf.read = (void*)read_bar;
|
||||||
|
streamfile->sf.get_size = (void*)get_size_bar;
|
||||||
|
streamfile->sf.get_offset = (void*)get_offset_bar;
|
||||||
|
streamfile->sf.get_name = (void*)get_name_bar;
|
||||||
|
streamfile->sf.get_realname = (void*)get_realname_bar;
|
||||||
|
streamfile->sf.open = (void*)open_bar;
|
||||||
|
streamfile->sf.close = (void*)close_bar;
|
||||||
|
#ifdef PROFILE_STREAMFILE
|
||||||
|
streamfile->sf.get_bytes_read = get_bytes_read_bar;
|
||||||
|
streamfile->sf.get_error_count = get_error_count_bar;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
streamfile->real_file = file;
|
||||||
|
|
||||||
|
return &streamfile->sf;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _GH3_BAR_STREAMFILE_H_ */
|
@ -1,31 +1,14 @@
|
|||||||
#include "meta.h"
|
#include "meta.h"
|
||||||
#include "../coding/coding.h"
|
#include "../coding/coding.h"
|
||||||
|
#include "sqex_scd_streamfile.h"
|
||||||
|
|
||||||
/* Square-Enix SCD (FF XIII, XIV) */
|
|
||||||
|
|
||||||
/* 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);
|
|
||||||
|
|
||||||
#ifdef VGM_USE_VORBIS
|
#ifdef VGM_USE_VORBIS
|
||||||
static void scd_ogg_decrypt_v2_callback(void *ptr, size_t size, size_t nmemb, void *datasource, int bytes_read);
|
static void scd_ogg_decrypt_v2_callback(void *ptr, size_t size, size_t nmemb, void *datasource, int bytes_read);
|
||||||
static void scd_ogg_decrypt_v3_callback(void *ptr, size_t size, size_t nmemb, void *datasource, int bytes_read);
|
static void scd_ogg_decrypt_v3_callback(void *ptr, size_t size, size_t nmemb, void *datasource, int bytes_read);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* SCD - Square-Enix console games (FF XIII, XIV) */
|
||||||
|
|
||||||
VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
|
VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
|
||||||
VGMSTREAM * vgmstream = NULL;
|
VGMSTREAM * vgmstream = NULL;
|
||||||
char filename[PATH_LIMIT];
|
char filename[PATH_LIMIT];
|
||||||
@ -34,39 +17,39 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
|
|||||||
int32_t loop_start, loop_end;
|
int32_t loop_start, loop_end;
|
||||||
|
|
||||||
int target_stream = streamFile->stream_index;
|
int target_stream = streamFile->stream_index;
|
||||||
int loop_flag = 0, channel_count, codec_id;
|
int loop_flag = 0, channel_count, codec_id, sample_rate;
|
||||||
int aux_chunk_count;
|
int aux_chunk_count;
|
||||||
|
|
||||||
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
|
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
|
||||||
int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;
|
int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;
|
||||||
|
|
||||||
|
|
||||||
/* check extension, case insensitive */
|
/* check extension, case insensitive */
|
||||||
if ( !check_extensions(streamFile, "scd") ) goto fail;
|
if ( !check_extensions(streamFile, "scd") ) goto fail;
|
||||||
|
|
||||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||||
|
|
||||||
/* SEDB */
|
/* SEDB */
|
||||||
if (read_32bitBE(0,streamFile) != 0x53454442) goto fail;
|
if (read_32bitBE(0x00,streamFile) != 0x53454442) goto fail;
|
||||||
/* SSCF */
|
/* SSCF */
|
||||||
if (read_32bitBE(4,streamFile) != 0x53534346) goto fail;
|
if (read_32bitBE(0x04,streamFile) != 0x53534346) goto fail;
|
||||||
|
|
||||||
/** main header section **/
|
/** main header section **/
|
||||||
if (read_32bitBE(8,streamFile) == 2 || /* version 2 BE, as seen in FFXIII demo for PS3 */
|
if (read_32bitBE(0x08,streamFile) == 2 || /* version 2 BE, as seen in FFXIII demo for PS3 */
|
||||||
read_32bitBE(8,streamFile) == 3) { /* version 3 BE, as seen in FFXIII for PS3 */
|
read_32bitBE(0x08,streamFile) == 3) { /* version 3 BE, as seen in FFXIII for PS3 */
|
||||||
|
|
||||||
read_32bit = read_32bitBE;
|
read_32bit = read_32bitBE;
|
||||||
read_16bit = read_16bitBE;
|
read_16bit = read_16bitBE;
|
||||||
//size_offset = 0x14;
|
//size_offset = 0x14;
|
||||||
} else if (read_32bitLE(8,streamFile) == 3 || /* version 2/3 LE, as seen in FFXIV for PC (and others?) */
|
} else if (read_32bitLE(0x08,streamFile) == 3 || /* version 2/3 LE, as seen in FFXIV for PC (and others?) */
|
||||||
read_32bitLE(8,streamFile) == 2) {
|
read_32bitLE(0x08,streamFile) == 2) {
|
||||||
|
|
||||||
read_32bit = read_32bitLE;
|
read_32bit = read_32bitLE;
|
||||||
read_16bit = read_16bitLE;
|
read_16bit = read_16bitLE;
|
||||||
//size_offset = 0x10;
|
//size_offset = 0x10;
|
||||||
} else goto fail;
|
} else goto fail;
|
||||||
|
|
||||||
/* 0xc: probably 00=LE, 01=BE */
|
/* 0x0c: probably 0=LE, 1=BE */
|
||||||
/* 0xd: unk (always 0x04) */
|
/* 0x0d: unk (always 0x04) */
|
||||||
tables_offset = read_16bit(0xe,streamFile);
|
tables_offset = read_16bit(0xe,streamFile);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
@ -97,14 +80,14 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
|
|||||||
meta_offset = read_32bit(headers_offset + (target_stream-1)*4,streamFile);
|
meta_offset = read_32bit(headers_offset + (target_stream-1)*4,streamFile);
|
||||||
|
|
||||||
/** stream header **/
|
/** stream header **/
|
||||||
stream_size = read_32bit(meta_offset + 0x0, streamFile);
|
stream_size = read_32bit(meta_offset+0x00, streamFile);
|
||||||
channel_count = read_32bit(meta_offset+4,streamFile);
|
channel_count = read_32bit(meta_offset+0x04,streamFile);
|
||||||
/* 0x8 sample rate */
|
sample_rate = read_32bit(meta_offset+0x08,streamFile);
|
||||||
codec_id = read_32bit(meta_offset+0xc,streamFile);
|
codec_id = read_32bit(meta_offset+0x0c,streamFile);
|
||||||
|
|
||||||
loop_start = read_32bit(meta_offset+0x10,streamFile);
|
loop_start = read_32bit(meta_offset+0x10,streamFile);
|
||||||
loop_end = read_32bit(meta_offset+0x14,streamFile);
|
loop_end = read_32bit(meta_offset+0x14,streamFile);
|
||||||
loop_flag = (loop_end > 0);
|
loop_flag = (loop_end > 0);
|
||||||
|
|
||||||
post_meta_offset = meta_offset + 0x20;
|
post_meta_offset = meta_offset + 0x20;
|
||||||
start_offset = post_meta_offset + read_32bit(meta_offset+0x18,streamFile);
|
start_offset = post_meta_offset + read_32bit(meta_offset+0x18,streamFile);
|
||||||
@ -123,18 +106,14 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef VGM_USE_VORBIS
|
#ifdef VGM_USE_VORBIS
|
||||||
/* special case using init_vgmstream_ogg_vorbis with callbacks */
|
/* special case using init_vgmstream_ogg_vorbis with callbacks */
|
||||||
if (codec_id == 0x6)
|
if (codec_id == 0x06) {
|
||||||
{
|
|
||||||
VGMSTREAM * result = NULL;
|
VGMSTREAM * result = NULL;
|
||||||
uint32_t seek_table_size, vorb_header_size;
|
uint32_t seek_table_size, vorb_header_size;
|
||||||
uint8_t xor_version, xor_byte;
|
uint8_t xor_version, xor_byte;
|
||||||
vgm_vorbis_info_t inf;
|
vgm_vorbis_info_t inf = {0};
|
||||||
|
|
||||||
|
|
||||||
memset(&inf, 0, sizeof(inf));
|
|
||||||
inf.loop_start = loop_start;
|
inf.loop_start = loop_start;
|
||||||
inf.loop_end = loop_end;
|
inf.loop_end = loop_end;
|
||||||
inf.loop_flag = loop_flag;
|
inf.loop_flag = loop_flag;
|
||||||
@ -205,13 +184,12 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
|
|||||||
|
|
||||||
/* fill in the vital statistics */
|
/* fill in the vital statistics */
|
||||||
vgmstream->channels = channel_count;
|
vgmstream->channels = channel_count;
|
||||||
vgmstream->sample_rate = read_32bit(meta_offset+8,streamFile);
|
vgmstream->sample_rate = sample_rate;
|
||||||
vgmstream->num_streams = headers_entries;
|
vgmstream->num_streams = headers_entries;
|
||||||
vgmstream->meta_type = meta_SQEX_SCD;
|
vgmstream->meta_type = meta_SQEX_SCD;
|
||||||
|
|
||||||
switch (codec_id) {
|
switch (codec_id) {
|
||||||
case 0x1:
|
case 0x01: /* PCM */
|
||||||
/* PCM */
|
|
||||||
vgmstream->coding_type = coding_PCM16_int;
|
vgmstream->coding_type = coding_PCM16_int;
|
||||||
vgmstream->layout_type = layout_none;
|
vgmstream->layout_type = layout_none;
|
||||||
vgmstream->num_samples = stream_size / 2 / channel_count;
|
vgmstream->num_samples = stream_size / 2 / channel_count;
|
||||||
@ -221,124 +199,111 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
|
|||||||
vgmstream->loop_end_sample = loop_end / 2 / channel_count;
|
vgmstream->loop_end_sample = loop_end / 2 / channel_count;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 0x06: /* OGG [Final Fantasy XIII-2 (PS3), Final Fantasy XIV (PC)] */
|
||||||
|
goto fail; /* handled above */
|
||||||
|
|
||||||
#ifdef VGM_USE_MPEG
|
#ifdef VGM_USE_MPEG
|
||||||
case 0x7:
|
case 0x07: { /* MPEG [Final Fantasy XIII (PS3)] */
|
||||||
/* MPEG */
|
mpeg_codec_data *mpeg_data = NULL;
|
||||||
{
|
|
||||||
mpeg_codec_data *mpeg_data = NULL;
|
|
||||||
coding_t ct;
|
|
||||||
|
|
||||||
/* Drakengard 3, some Kingdom Hearts */
|
/* Drakengard 3, some Kingdom Hearts */
|
||||||
if (vgmstream->sample_rate == 47999)
|
if (vgmstream->sample_rate == 47999)
|
||||||
vgmstream->sample_rate = 48000;
|
vgmstream->sample_rate = 48000;
|
||||||
if (vgmstream->sample_rate == 44099)
|
if (vgmstream->sample_rate == 44099)
|
||||||
vgmstream->sample_rate = 44100;
|
vgmstream->sample_rate = 44100;
|
||||||
|
|
||||||
mpeg_data = init_mpeg_codec_data(streamFile, start_offset, &ct, vgmstream->channels);
|
mpeg_data = init_mpeg_codec_data(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels);
|
||||||
if (!mpeg_data) goto fail;
|
if (!mpeg_data) goto fail;
|
||||||
vgmstream->codec_data = mpeg_data;
|
vgmstream->codec_data = mpeg_data;
|
||||||
|
vgmstream->layout_type = layout_none;
|
||||||
|
|
||||||
vgmstream->coding_type = ct;
|
vgmstream->num_samples = mpeg_bytes_to_samples(stream_size, mpeg_data);
|
||||||
vgmstream->layout_type = layout_none;
|
vgmstream->num_samples -= vgmstream->num_samples%576;
|
||||||
vgmstream->num_samples = mpeg_bytes_to_samples(stream_size, mpeg_data);
|
if (loop_flag) {
|
||||||
vgmstream->num_samples -= vgmstream->num_samples%576;
|
vgmstream->loop_start_sample = mpeg_bytes_to_samples(loop_start, mpeg_data);
|
||||||
if (loop_flag) {
|
vgmstream->loop_start_sample -= vgmstream->loop_start_sample%576;
|
||||||
vgmstream->loop_start_sample = mpeg_bytes_to_samples(loop_start, mpeg_data);
|
vgmstream->loop_end_sample = mpeg_bytes_to_samples(loop_end, mpeg_data);
|
||||||
vgmstream->loop_start_sample -= vgmstream->loop_start_sample%576;
|
vgmstream->loop_end_sample -= vgmstream->loop_end_sample%576;
|
||||||
vgmstream->loop_end_sample = mpeg_bytes_to_samples(loop_end, mpeg_data);
|
|
||||||
vgmstream->loop_end_sample -= vgmstream->loop_end_sample%576;
|
|
||||||
}
|
|
||||||
vgmstream->interleave_block_size = 0;
|
|
||||||
}
|
}
|
||||||
|
vgmstream->interleave_block_size = 0;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
case 0xC:
|
case 0x0C: /* MS ADPCM [Final Fantasy XIV (PC) sfx] */
|
||||||
/* MS ADPCM */
|
|
||||||
vgmstream->coding_type = coding_MSADPCM;
|
vgmstream->coding_type = coding_MSADPCM;
|
||||||
vgmstream->layout_type = layout_none;
|
vgmstream->layout_type = layout_none;
|
||||||
vgmstream->interleave_block_size = read_16bit(post_meta_offset+0xc,streamFile);
|
vgmstream->interleave_block_size = read_16bit(post_meta_offset+0x0c,streamFile);
|
||||||
vgmstream->num_samples = msadpcm_bytes_to_samples(stream_size, vgmstream->interleave_block_size, vgmstream->channels);
|
|
||||||
|
|
||||||
|
vgmstream->num_samples = msadpcm_bytes_to_samples(stream_size, vgmstream->interleave_block_size, vgmstream->channels);
|
||||||
if (loop_flag) {
|
if (loop_flag) {
|
||||||
vgmstream->loop_start_sample = msadpcm_bytes_to_samples(loop_start, vgmstream->interleave_block_size, vgmstream->channels);
|
vgmstream->loop_start_sample = msadpcm_bytes_to_samples(loop_start, vgmstream->interleave_block_size, vgmstream->channels);
|
||||||
vgmstream->loop_end_sample = msadpcm_bytes_to_samples(loop_end, vgmstream->interleave_block_size, vgmstream->channels);
|
vgmstream->loop_end_sample = msadpcm_bytes_to_samples(loop_end, vgmstream->interleave_block_size, vgmstream->channels);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xA: /* Dragon Quest X (Wii) */
|
case 0x0A: /* DSP ADPCM [Dragon Quest X (Wii)] */
|
||||||
case 0x15: /* Dragon Quest X (Wii U) (no apparent differences except higher sample rate) */
|
case 0x15: { /* DSP ADPCM [Dragon Quest X (Wii U)] (no apparent differences except higher sample rate) */
|
||||||
/* GC/Wii DSP ADPCM */
|
STREAMFILE * file;
|
||||||
{
|
int i;
|
||||||
STREAMFILE * file;
|
const off_t interleave_size = 0x800;
|
||||||
int i;
|
const off_t stride_size = interleave_size * channel_count;
|
||||||
const off_t interleave_size = 0x800;
|
size_t total_size;
|
||||||
const off_t stride_size = interleave_size * channel_count;
|
scd_int_codec_data * data = NULL;
|
||||||
|
|
||||||
size_t total_size;
|
|
||||||
|
|
||||||
scd_int_codec_data * data = NULL;
|
vgmstream->coding_type = coding_NGC_DSP;
|
||||||
|
vgmstream->layout_type = layout_scd_int;
|
||||||
vgmstream->coding_type = coding_NGC_DSP;
|
|
||||||
vgmstream->layout_type = layout_scd_int;
|
|
||||||
|
|
||||||
/* a normal DSP header... */
|
|
||||||
vgmstream->num_samples = read_32bitBE(start_offset+0,streamFile);
|
|
||||||
total_size = (read_32bitBE(start_offset+4,streamFile)+1)/2;
|
|
||||||
|
|
||||||
if (loop_flag) {
|
|
||||||
vgmstream->loop_start_sample = loop_start;
|
|
||||||
vgmstream->loop_end_sample = loop_end+1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* verify other channel headers */
|
|
||||||
for (i = 1; i < channel_count; i++) {
|
|
||||||
if (read_32bitBE(start_offset+interleave_size*i+0,streamFile) != vgmstream->num_samples ||
|
|
||||||
(read_32bitBE(start_offset+4,streamFile)+1)/2 != total_size) {
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* the primary streamfile we'll be using */
|
|
||||||
file = streamFile->open(streamFile,filename,stride_size);
|
|
||||||
if (!file)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
vgmstream->ch[0].streamfile = file;
|
|
||||||
|
|
||||||
data = malloc(sizeof(scd_int_codec_data));
|
|
||||||
data->substream_count = channel_count;
|
|
||||||
data->substreams = calloc(channel_count, sizeof(VGMSTREAM *));
|
|
||||||
data->intfiles = calloc(channel_count, sizeof(STREAMFILE *));
|
|
||||||
|
|
||||||
vgmstream->codec_data = data;
|
|
||||||
|
|
||||||
for (i=0;i<channel_count;i++) {
|
|
||||||
STREAMFILE * intfile =
|
|
||||||
open_scdint_with_STREAMFILE(file, "ARBITRARY.DSP", start_offset+interleave_size*i, interleave_size, stride_size, total_size);
|
|
||||||
if (!intfile)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
data->substreams[i] = init_vgmstream_ngc_dsp_std(intfile);
|
|
||||||
data->intfiles[i] = intfile;
|
|
||||||
if (!data->substreams[i])
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
/* TODO: only handles mono substreams, though that's all we have with DSP */
|
|
||||||
/* save start things so we can restart for seeking/looping */
|
|
||||||
/* copy the channels */
|
|
||||||
memcpy(data->substreams[i]->start_ch,data->substreams[i]->ch,sizeof(VGMSTREAMCHANNEL)*1);
|
|
||||||
/* copy the whole VGMSTREAM */
|
|
||||||
memcpy(data->substreams[i]->start_vgmstream,data->substreams[i],sizeof(VGMSTREAM));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/* a normal DSP header... */
|
||||||
|
total_size = (read_32bitBE(start_offset+0x04,streamFile)+1)/2;
|
||||||
|
vgmstream->num_samples = read_32bitBE(start_offset+0x00,streamFile);
|
||||||
|
if (loop_flag) {
|
||||||
|
vgmstream->loop_start_sample = loop_start;
|
||||||
|
vgmstream->loop_end_sample = loop_end+1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* verify other channel headers */
|
||||||
|
for (i = 1; i < channel_count; i++) {
|
||||||
|
if (read_32bitBE(start_offset+interleave_size*i+0,streamFile) != vgmstream->num_samples ||
|
||||||
|
(read_32bitBE(start_offset+4,streamFile)+1)/2 != total_size) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* the primary streamfile we'll be using */
|
||||||
|
file = streamFile->open(streamFile,filename,stride_size);
|
||||||
|
if (!file) goto fail;
|
||||||
|
|
||||||
|
vgmstream->ch[0].streamfile = file;
|
||||||
|
|
||||||
|
data = malloc(sizeof(scd_int_codec_data));
|
||||||
|
data->substream_count = channel_count;
|
||||||
|
data->substreams = calloc(channel_count, sizeof(VGMSTREAM *));
|
||||||
|
data->intfiles = calloc(channel_count, sizeof(STREAMFILE *));
|
||||||
|
|
||||||
|
vgmstream->codec_data = data;
|
||||||
|
|
||||||
|
for (i=0;i<channel_count;i++) {
|
||||||
|
STREAMFILE * intfile =
|
||||||
|
open_scdint_with_STREAMFILE(file, "ARBITRARY.DSP", start_offset+interleave_size*i, interleave_size, stride_size, total_size);
|
||||||
|
if (!intfile) goto fail;
|
||||||
|
|
||||||
|
data->substreams[i] = init_vgmstream_ngc_dsp_std(intfile);
|
||||||
|
data->intfiles[i] = intfile;
|
||||||
|
if (!data->substreams[i]) goto fail;
|
||||||
|
|
||||||
|
/* TODO: only handles mono substreams, though that's all we have with DSP */
|
||||||
|
/* save start things so we can restart for seeking/looping */
|
||||||
|
memcpy(data->substreams[i]->start_ch,data->substreams[i]->ch,sizeof(VGMSTREAMCHANNEL)*1);
|
||||||
|
memcpy(data->substreams[i]->start_vgmstream,data->substreams[i],sizeof(VGMSTREAM));
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef VGM_USE_FFMPEG
|
#ifdef VGM_USE_FFMPEG
|
||||||
case 0xB:
|
case 0x0B: { /* XMA2 [Final Fantasy (X360), Lightning Returns (X360) sfx] */
|
||||||
/* XMA2 */ /* Lightning Returns SFX, FFXIII (X360) */
|
|
||||||
{
|
|
||||||
ffmpeg_codec_data *ffmpeg_data = NULL;
|
ffmpeg_codec_data *ffmpeg_data = NULL;
|
||||||
uint8_t buf[200];
|
uint8_t buf[200];
|
||||||
int32_t bytes;
|
int32_t bytes;
|
||||||
@ -356,44 +321,42 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
|
|||||||
vgmstream->num_samples = ffmpeg_data->totalSamples;
|
vgmstream->num_samples = ffmpeg_data->totalSamples;
|
||||||
vgmstream->loop_start_sample = loop_start;
|
vgmstream->loop_start_sample = loop_start;
|
||||||
vgmstream->loop_end_sample = loop_end;
|
vgmstream->loop_end_sample = loop_end;
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 0xE:
|
case 0x0E: { /* ATRAC3plus [Lord of Arcana (PSP)] */
|
||||||
/* ATRAC3plus */ /* Lord of Arcana (PSP) */
|
ffmpeg_codec_data *ffmpeg_data = NULL;
|
||||||
{
|
|
||||||
ffmpeg_codec_data *ffmpeg_data = NULL;
|
|
||||||
|
|
||||||
/* full RIFF header at start_offset/post_meta_offset (same) */
|
/* full RIFF header at start_offset/post_meta_offset (same) */
|
||||||
ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset,stream_size);
|
ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset,stream_size);
|
||||||
if (!ffmpeg_data) goto fail;
|
if (!ffmpeg_data) goto fail;
|
||||||
vgmstream->codec_data = ffmpeg_data;
|
vgmstream->codec_data = ffmpeg_data;
|
||||||
vgmstream->coding_type = coding_FFmpeg;
|
vgmstream->coding_type = coding_FFmpeg;
|
||||||
vgmstream->layout_type = layout_none;
|
vgmstream->layout_type = layout_none;
|
||||||
|
|
||||||
vgmstream->num_samples = ffmpeg_data->totalSamples; /* fact samples */
|
vgmstream->num_samples = ffmpeg_data->totalSamples; /* fact samples */
|
||||||
vgmstream->loop_start_sample = loop_start;
|
vgmstream->loop_start_sample = loop_start;
|
||||||
vgmstream->loop_end_sample = loop_end;
|
vgmstream->loop_end_sample = loop_end;
|
||||||
|
|
||||||
/* manually read skip_samples if FFmpeg didn't do it */
|
/* manually read skip_samples if FFmpeg didn't do it */
|
||||||
if (ffmpeg_data->skipSamples <= 0) {
|
if (ffmpeg_data->skipSamples <= 0) {
|
||||||
off_t chunk_offset;
|
off_t chunk_offset;
|
||||||
size_t chunk_size, fact_skip_samples = 0;
|
size_t chunk_size, fact_skip_samples = 0;
|
||||||
if (!find_chunk_le(streamFile, 0x66616374,start_offset+0xc,0, &chunk_offset,&chunk_size)) /* find "fact" */
|
if (!find_chunk_le(streamFile, 0x66616374,start_offset+0xc,0, &chunk_offset,&chunk_size)) /* find "fact" */
|
||||||
goto fail;
|
goto fail;
|
||||||
if (chunk_size == 0x8) {
|
if (chunk_size == 0x8) {
|
||||||
fact_skip_samples = read_32bitLE(chunk_offset+0x4, streamFile);
|
fact_skip_samples = read_32bitLE(chunk_offset+0x4, streamFile);
|
||||||
} else if (chunk_size == 0xc) {
|
} else if (chunk_size == 0xc) {
|
||||||
fact_skip_samples = read_32bitLE(chunk_offset+0x8, streamFile);
|
fact_skip_samples = read_32bitLE(chunk_offset+0x8, streamFile);
|
||||||
}
|
|
||||||
ffmpeg_set_skip_samples(ffmpeg_data, fact_skip_samples);
|
|
||||||
}
|
}
|
||||||
/* SCD loop/sample values are relative (without skip samples) vs RIFF (with skip samples), no need to adjust */
|
ffmpeg_set_skip_samples(ffmpeg_data, fact_skip_samples);
|
||||||
|
|
||||||
}
|
}
|
||||||
break;
|
/* SCD loop/sample values are relative (without skip samples) vs RIFF (with skip samples), no need to adjust */
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
default:
|
default:
|
||||||
VGM_LOG("SCD: unknown codec_id 0x%x\n", codec_id);
|
VGM_LOG("SCD: unknown codec_id 0x%x\n", codec_id);
|
||||||
goto fail;
|
goto fail;
|
||||||
@ -410,131 +373,6 @@ fail:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
/* an error which we will not attempt to handle here */
|
|
||||||
return sz;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef VGM_USE_VORBIS
|
#ifdef VGM_USE_VORBIS
|
||||||
static void scd_ogg_decrypt_v2_callback(void *ptr, size_t size, size_t nmemb, void *datasource, int bytes_read) {
|
static void scd_ogg_decrypt_v2_callback(void *ptr, size_t size, size_t nmemb, void *datasource, int bytes_read) {
|
||||||
|
134
src/meta/sqex_scd_streamfile.h
Normal file
134
src/meta/sqex_scd_streamfile.h
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
#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_ */
|
Loading…
Reference in New Issue
Block a user