cleanup: separate functions

This commit is contained in:
bnnm 2023-05-14 23:20:20 +02:00
parent bf218c08b4
commit 4b0387fb7a
38 changed files with 384 additions and 314 deletions

View File

@ -1,5 +1,6 @@
#include "coding.h"
#include "../util/channel_mappings.h"
#include "../util/chunks.h"
#ifdef VGM_USE_FFMPEG

View File

@ -171,15 +171,18 @@
<ClInclude Include="util\bitstream_msb.h" />
<ClInclude Include="util\channel_mappings.h" />
<ClInclude Include="util\chunks.h" />
<ClInclude Include="util\companion_files.h" />
<ClInclude Include="util\cri_keys.h" />
<ClInclude Include="util\cri_utf.h" />
<ClInclude Include="util\endianness.h" />
<ClInclude Include="util\log.h" />
<ClInclude Include="util\m2_psb.h" />
<ClInclude Include="util\miniz.h" />
<ClInclude Include="util\paths.h" />
<ClInclude Include="util\reader_get.h" />
<ClInclude Include="util\reader_get_nibbles.h" />
<ClInclude Include="util\reader_put.h" />
<ClInclude Include="util\reader_sf.h" />
<ClInclude Include="util\samples_ops.h" />
<ClInclude Include="util\text_reader.h" />
</ItemGroup>
@ -736,11 +739,13 @@
<ClCompile Include="meta\zwdsp.c" />
<ClCompile Include="meta\zwv.c" />
<ClCompile Include="util\chunks.c" />
<ClCompile Include="util\companion_files.c" />
<ClCompile Include="util\cri_keys.c" />
<ClCompile Include="util\cri_utf.c" />
<ClCompile Include="util\log.c" />
<ClCompile Include="util\m2_psb.c" />
<ClCompile Include="util\miniz.c" />
<ClCompile Include="util\paths.c" />
<ClCompile Include="util\reader_put.c" />
<ClCompile Include="util\samples_ops.c" />
<ClCompile Include="util\text_reader.c" />

View File

@ -338,6 +338,9 @@
<ClInclude Include="util\chunks.h">
<Filter>util\Header Files</Filter>
</ClInclude>
<ClInclude Include="util\companion_files.h">
<Filter>util\Header Files</Filter>
</ClInclude>
<ClInclude Include="util\cri_keys.h">
<Filter>util\Header Files</Filter>
</ClInclude>
@ -356,6 +359,9 @@
<ClInclude Include="util\miniz.h">
<Filter>util\Header Files</Filter>
</ClInclude>
<ClInclude Include="util\paths.h">
<Filter>util\Header Files</Filter>
</ClInclude>
<ClInclude Include="util\reader_get.h">
<Filter>util\Header Files</Filter>
</ClInclude>
@ -365,6 +371,9 @@
<ClInclude Include="util\reader_put.h">
<Filter>util\Header Files</Filter>
</ClInclude>
<ClInclude Include="util\reader_sf.h">
<Filter>util\Header Files</Filter>
</ClInclude>
<ClInclude Include="util\samples_ops.h">
<Filter>util\Header Files</Filter>
</ClInclude>
@ -2029,6 +2038,9 @@
<ClCompile Include="util\chunks.c">
<Filter>util\Source Files</Filter>
</ClCompile>
<ClCompile Include="util\companion_files.c">
<Filter>util\Source Files</Filter>
</ClCompile>
<ClCompile Include="util\cri_keys.c">
<Filter>util\Source Files</Filter>
</ClCompile>
@ -2044,6 +2056,9 @@
<ClCompile Include="util\miniz.c">
<Filter>util\Source Files</Filter>
</ClCompile>
<ClCompile Include="util\paths.c">
<Filter>util\Source Files</Filter>
</ClCompile>
<ClCompile Include="util\reader_put.c">
<Filter>util\Source Files</Filter>
</ClCompile>

View File

@ -7,6 +7,7 @@
#include "adx_keys.h"
#include "../coding/coding.h"
#include "../util/cri_keys.h"
#include "../util/companion_files.h"
#ifdef VGM_DEBUG_OUTPUT

View File

@ -2,6 +2,7 @@
#include "../coding/coding.h"
#include "ahx_keys.h"
#include "../util/cri_keys.h"
#include "../util/companion_files.h"
#ifdef VGM_USE_MPEG
static int find_ahx_key(STREAMFILE* sf, off_t offset, crikey_t* crikey);

View File

@ -1,5 +1,6 @@
#include "meta.h"
#include "../coding/coding.h"
#include "../util/companion_files.h"
//typedef enum { ADX, HCA, VAG, RIFF, CWAV, DSP, CWAC, M4A } awb_type_t;

View File

@ -1,6 +1,7 @@
#include "meta.h"
#include "../coding/coding.h"
#include "../util/chunks.h"
#include "../util/companion_files.h"
#include "bnsf_keys.h"

View File

@ -1,6 +1,7 @@
#include "meta.h"
#include "../coding/coding.h"
#include "../util/cri_utf.h"
#include "../util/companion_files.h"
typedef enum { HCA, CWAV, ADX } cpk_type_t;

View File

@ -1,5 +1,6 @@
#include "meta.h"
#include "../coding/coding.h"
#include "../util/chunks.h"
/* CSMP - Retro Studios sample [Metroid Prime 3 (Wii)-sfx, Donkey Kong Country Returns (Wii)-sfx] */

View File

@ -3,6 +3,7 @@
#include "../layout/layout.h"
#include "../coding/coding.h"
#include "../util/endianness.h"
#include "../util/companion_files.h"
#include "ea_eaac_streamfile.h"
/* EAAudioCore (aka SND10) formats, EA's current audio middleware */

View File

@ -2,6 +2,7 @@
#include "../layout/layout.h"
#include "../coding/coding.h"
#include "../util/endianness.h"
#include "../util/companion_files.h"
#include "ea_schl_streamfile.h"
/* header version */

View File

@ -1,5 +1,7 @@
#include "meta.h"
#include "../coding/coding.h"
#include "../util/companion_files.h"
#include "../util/chunks.h"
#include "ogg_vorbis_streamfile.h"
#include "encrypted_bgm_streamfile.h"
#include "encrypted_mc161_streamfile.h"

View File

@ -1,5 +1,6 @@
#include "meta.h"
#include "../coding/coding.h"
#include "../util/chunks.h"
static int get_subsongs(STREAMFILE* sf, off_t fsb5_offset, size_t fsb5_size);
@ -16,13 +17,14 @@ VGMSTREAM* init_vgmstream_fsb5_fev_bank(STREAMFILE* sf) {
/* checks */
if (!is_id32be(0x00,sf, "RIFF"))
goto fail;
if (!is_id32be(0x08,sf, "FEV "))
goto fail;
if (!check_extensions(sf, "bank"))
goto fail;
if (read_u32be(0x00,sf) != 0x52494646) /* "RIFF" */
goto fail;
if (read_u32be(0x08,sf) != 0x46455620) /* "FEV " */
goto fail;
version = read_u32le(0x14,sf); /* newer FEV have some kind of sub-version at 0x18 */
/* .fev is an event format referencing various external .fsb, but FMOD can bake .fev and .fsb to

View File

@ -1,4 +1,5 @@
#include "meta.h"
#include "../util/companion_files.h"
#include "fsb_keys.h"
#include "fsb_encrypted_streamfile.h"

View File

@ -1,6 +1,7 @@
#include "meta.h"
#include "../layout/layout.h"
#include "../coding/coding.h"
#include "../util/chunks.h"
/* GSP+GSB - from Tecmo's Super Swing Golf 1 & 2 (Wii), Quantum Theory (PS3/X360) */
VGMSTREAM* init_vgmstream_gsp_gsb(STREAMFILE* sf) {

View File

@ -3,6 +3,7 @@
#include "../coding/coding.h"
#include "../coding/hca_decoder_clhca.h"
#include "../util/channel_mappings.h"
#include "../util/companion_files.h"
#ifdef VGM_DEBUG_OUTPUT
//#define HCA_BRUTEFORCE

View File

@ -1,5 +1,6 @@
#include "meta.h"
#include "../coding/coding.h"
#include "../util/chunks.h"
/* LucasArts iMUSE (Interactive Music Streaming Engine) formats */

View File

@ -1,6 +1,7 @@
#include "meta.h"
#include "../coding/coding.h"
#include "../util/endianness.h"
#include "../util/chunks.h"
static void load_name(char* name, size_t name_size, STREAMFILE* sf, int big_endian, int total_subsongs, int target_subsong);
@ -20,17 +21,17 @@ VGMSTREAM* init_vgmstream_nub(STREAMFILE* sf) {
/* checks */
/* .nub: standard
* .nub2: rare [iDOLM@STER - Gravure For You (PS3)] */
if (!check_extensions(sf, "nub,nub2"))
goto fail;
version = read_32bitBE(0x00,sf);
version = read_u32be(0x00,sf);
if (version != 0x00020000 && /* v2.0 (rare, ex. Ridge Race 6 (X360)) */
version != 0x00020100 && /* v2.1 (common) */
version != 0x01020100) /* same but LE (seen in PSP/PC games, except PS4) */
goto fail;
if (read_32bitBE(0x04,sf) != 0x00000000) /* null */
if (read_u32be(0x04,sf) != 0x00000000) /* null */
goto fail;
/* .nub: standard
* .nub2: rare [iDOLM@STER - Gravure For You (PS3)] */
if (!check_extensions(sf, "nub,nub2"))
goto fail;
/* sometimes LE [Soul Calibur: Broken Destiny (PSP), Tales of Vesperia (PS4) */

View File

@ -1,5 +1,7 @@
#include "meta.h"
#include "../coding/coding.h"
#include "../util/chunks.h"
/* .SBK - from Addiction Pinball (PC) */
VGMSTREAM *init_vgmstream_sbk(STREAMFILE *sf) {
@ -11,13 +13,12 @@ VGMSTREAM *init_vgmstream_sbk(STREAMFILE *sf) {
int target_subsong = sf->stream_index, total_subsongs, loop_flag, is_streamed;
/* checks */
if (!check_extensions(sf, "sbk"))
if (!is_id32be(0x00,sf, "RIFF"))
goto fail;
if (!is_id32be(0x08,sf, "SBNK"))
goto fail;
/* check header */
if (read_u32be(0x00, sf) != 0x52494646) /* "RIFF" */
goto fail;
if (read_u32be(0x08, sf) != 0x53424E4B) /* "SBNK" */
if (!check_extensions(sf, "sbk"))
goto fail;
if (!find_chunk_le(sf, 0x57415649, 0x0c, 0, &table_offset, &table_size)) /* "WAVI" */

View File

@ -1,5 +1,6 @@
#include "meta.h"
#include "../coding/coding.h"
#include "../util/chunks.h"
/* SGXD - Sony/SCEI's format (SGB+SGH / SGD / SGX) */

View File

@ -1,5 +1,6 @@
#include "meta.h"
#include "../coding/coding.h"
#include "../util/chunks.h"
/* SXD - Sony/SCE's SNDX lib format (cousin of SGXD) [Gravity Rush, Freedom Wars, Soul Sacrifice PSV] */

View File

@ -4,6 +4,7 @@
#include "txth_streamfile.h"
#include "../util/text_reader.h"
#include "../util/endianness.h"
#include "../util/paths.h"
#define TXT_LINE_MAX 2048 /* probably ~1000 would be ok */
#define TXT_LINE_KEY_MAX 128

View File

@ -4,6 +4,7 @@
#include "../base/mixing.h"
#include "../base/plugins.h"
#include "../util/text_reader.h"
#include "../util/paths.h"
#include <math.h>

View File

@ -1,6 +1,7 @@
#include "meta.h"
#include "../coding/coding.h"
#include "../util/endianness.h"
#include "../util/chunks.h"
typedef enum { MSADPCM, DSP, MP3, XMA2 } ckd_codec;

View File

@ -2,6 +2,7 @@
#include "../layout/layout.h"
#include "../coding/coding.h"
#include "../util/endianness.h"
#include "../util/chunks.h"
typedef enum { PCM, UBI, PSX, DSP, XIMA, ATRAC3, XMA2, MP3, SILENCE } ubi_hx_codec;

View File

@ -1,5 +1,6 @@
#include "meta.h"
#include "../coding/coding.h"
#include "../util/chunks.h"
/* VXN - from Gameloft mobile games */
@ -11,11 +12,12 @@ VGMSTREAM* init_vgmstream_vxn(STREAMFILE* sf) {
int total_subsongs, target_subsong = sf->stream_index;
/* checks */
if (!is_id32be(0x00,sf, "VoxN"))
goto fail;
if (!check_extensions(sf,"vxn"))
goto fail;
if (!is_id32be(0x00,sf, "VoxN"))
goto fail;
/* 0x04: chunk size */
/* 0x08: ASCII version? ("0.0.1") */
if (read_u32le(0x10,sf) != get_streamfile_size(sf))

View File

@ -1,5 +1,6 @@
#include "meta.h"
#include "../coding/coding.h"
#include "../util/chunks.h"
//#include <ctype.h>
/* .WBK - seen in some Treyarch games [Spider-Man 2, Ultimate Spider-Man, Call of Duty 2: Big Red One] */

View File

@ -1,64 +1,65 @@
#include "meta.h"
#include "../util.h"
#include "../coding/coding.h"
#include "../util/chunks.h"
/* XAU - XPEC Entertainment sound format (Beat Down PS2/Xbox, Spectral Force Chronicle [SLPM-65967]) */
VGMSTREAM * init_vgmstream_xau(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
/* XAU - XPEC Entertainment sound format [Beat Down (PS2/Xbox), Spectral Force Chronicle (PS2)] */
VGMSTREAM* init_vgmstream_xau(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count, type, loop_start, loop_end;
int loop_flag, channels, type, loop_start, loop_end;
/* check extension */
if (!check_extensions(streamFile, "xau"))
goto fail;
/* check header */
if (read_32bitBE(0x00,streamFile) != 0x58415500) /* "XAU\0" "*/
if (!is_id32be(0x00,sf, "XAU\0"))
goto fail;
if (read_32bitLE(0x08,streamFile) != 0x40) /* header start */
if (!check_extensions(sf, "xau"))
goto fail;
if (read_32bitLE(0x08,sf) != 0x40) /* header start */
goto fail;
/* 0x04: version? (0x100) */
type = read_32bitBE(0x0c, streamFile);
loop_start = read_32bitLE(0x10, streamFile);
loop_end = read_32bitLE(0x14, streamFile);
loop_flag = (loop_end > 0);
type = read_32bitBE(0x0c, sf);
loop_start = read_32bitLE(0x10, sf);
loop_end = read_32bitLE(0x14, sf);
loop_flag = (loop_end > 0);
channel_count = read_8bit(0x18,streamFile);
channels = read_8bit(0x18,sf);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->channels = channel_count;
vgmstream->channels = channels;
vgmstream->meta_type = meta_XAU;
/* miniheader over a common header with some tweaks, so we'll simplify parsing */
switch(type) {
case 0x50533200: /* "PS2\0" */
if (read_32bitBE(0x40,streamFile) != 0x56414770) goto fail; /* mutant "VAGp" (long header size) */
/* miniheader over a common header with some tweaks, so we'll simplify parsing */
switch(type) {
case 0x50533200: /* "PS2\0" */
if (read_32bitBE(0x40,sf) != 0x56414770) goto fail; /* mutant "VAGp" (long header size) */
start_offset = 0x800;
vgmstream->sample_rate = read_32bitBE(0x50, streamFile);
vgmstream->num_samples = ps_bytes_to_samples(read_32bitBE(0x4C,streamFile) * channel_count, channel_count);
start_offset = 0x800;
vgmstream->sample_rate = read_32bitBE(0x50, sf);
vgmstream->num_samples = ps_bytes_to_samples(read_32bitBE(0x4C,sf) * channels, channels);
vgmstream->loop_start_sample = loop_start;
vgmstream->loop_end_sample = loop_end;
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x8000;
break;
vgmstream->interleave_block_size = 0x8000;
break;
case 0x58420000: /* "XB\0\0" */
if (read_32bitBE(0x40,streamFile) != 0x52494646) goto fail; /* mutant "RIFF" (sometimes wrong RIFF size) */
case 0x58420000: /* "XB\0\0" */
if (read_32bitBE(0x40,sf) != 0x52494646) goto fail; /* mutant "RIFF" (sometimes wrong RIFF size) */
/* start offset: find "data" chunk, as sometimes there is a "smpl" chunk at the start or the end (same as loop_start/end) */
if (!find_chunk_le(streamFile, 0x64617461, 0x4c, 0, &start_offset, NULL) )
goto fail;
/* start offset: find "data" chunk, as sometimes there is a "smpl" chunk at the start or the end (same as loop_start/end) */
if (!find_chunk_le(sf, 0x64617461, 0x4c, 0, &start_offset, NULL) )
goto fail;
vgmstream->sample_rate = read_32bitLE(0x58, streamFile);
vgmstream->num_samples = xbox_ima_bytes_to_samples(read_32bitLE(start_offset-4, streamFile), channel_count);
vgmstream->sample_rate = read_32bitLE(0x58, sf);
vgmstream->num_samples = xbox_ima_bytes_to_samples(read_32bitLE(start_offset-4, sf), channels);
vgmstream->loop_start_sample = loop_start;
vgmstream->loop_end_sample = loop_end;
@ -66,13 +67,13 @@ VGMSTREAM * init_vgmstream_xau(STREAMFILE *streamFile) {
vgmstream->layout_type = layout_none;
break;
default:
goto fail;
}
default:
goto fail;
}
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
if (!vgmstream_open_stream(vgmstream,sf,start_offset))
goto fail;
return vgmstream;

View File

@ -2,6 +2,7 @@
#include "../coding/coding.h"
#include "../layout/layout.h"
#include "xvag_streamfile.h"
#include "../util/chunks.h"
typedef struct {
@ -41,12 +42,13 @@ VGMSTREAM* init_vgmstream_xvag(STREAMFILE* sf) {
/* checks */
if (!is_id32be(0x00,sf, "XVAG"))
goto fail;
/* .xvag: standard
* (extensionless): The Last of Us (PS3) speech files */
if (!check_extensions(sf,"xvag,"))
goto fail;
if (!is_id32be(0x00,sf, "XVAG"))
goto fail;
/* endian flag (XVAGs of the same game can use BE or LE, usually when reusing from other platforms) */
xvag.big_endian = read_8bit(0x08,sf) & 0x01;

View File

@ -1,6 +1,7 @@
#ifndef _XWB_XSB_H_
#define _XWB_XSB_H_
#include "meta.h"
#include "../util/companion_files.h"
#define XSB_XACT1_0_MAX 5 /* Unreal Championship (Xbox) */
#define XSB_XACT1_1_MAX 8 /* Die Hard: Vendetta (Xbox) */

View File

@ -2,6 +2,7 @@
#include "util.h"
#include "vgmstream.h"
#include "util/reader_sf.h"
#include "util/paths.h"
#include <string.h>
/* for dup/fdopen in some systems */
@ -9,15 +10,6 @@
#include <unistd.h>
#endif
//TODO: move
#ifndef DIR_SEPARATOR
#if defined (_WIN32) || defined (WIN32)
#define DIR_SEPARATOR '\\'
#else
#define DIR_SEPARATOR '/'
#endif
#endif
/* For (rarely needed) +2GB file support we use fseek64/ftell64. Those are usually available
* but may depend on compiler.
* - MSVC: +VS2008 should work
@ -1205,162 +1197,6 @@ size_t read_string_utf16be(char* buf, size_t buf_size, off_t offset, STREAMFILE*
/* ************************************************************************* */
size_t read_key_file(uint8_t* buf, size_t buf_size, STREAMFILE* sf) {
char keyname[PATH_LIMIT];
char filename[PATH_LIMIT];
const char *path, *ext;
STREAMFILE* sf_key = NULL;
size_t keysize;
get_streamfile_name(sf, filename, sizeof(filename));
if (strlen(filename)+4 > sizeof(keyname)) goto fail;
/* try to open a keyfile using variations */
{
ext = strrchr(filename,'.');
if (ext!=NULL) ext = ext+1;
path = strrchr(filename, DIR_SEPARATOR);
if (path!=NULL) path = path+1;
/* "(name.ext)key" */
strcpy(keyname, filename);
strcat(keyname, "key");
sf_key = sf->open(sf, keyname, STREAMFILE_DEFAULT_BUFFER_SIZE);
if (sf_key) goto found;
/* "(name.ext)KEY" */
/*
strcpy(keyname+strlen(keyname)-3,"KEY");
sf_key = sf->open(sf, keyname, STREAMFILE_DEFAULT_BUFFER_SIZE);
if (sf_key) goto found;
*/
/* "(.ext)key" */
if (path) {
strcpy(keyname, filename);
keyname[path-filename] = '\0';
strcat(keyname, ".");
} else {
strcpy(keyname, ".");
}
if (ext) strcat(keyname, ext);
strcat(keyname, "key");
sf_key = sf->open(sf, keyname, STREAMFILE_DEFAULT_BUFFER_SIZE);
if (sf_key) goto found;
/* "(.ext)KEY" */
/*
strcpy(keyname+strlen(keyname)-3,"KEY");
sf_key = sf->open(sf, keyname, STREAMFILE_DEFAULT_BUFFER_SIZE);
if (sf_key) goto found;
*/
goto fail;
}
found:
keysize = get_streamfile_size(sf_key);
if (keysize > buf_size) goto fail;
if (read_streamfile(buf, 0, keysize, sf_key) != keysize)
goto fail;
close_streamfile(sf_key);
return keysize;
fail:
close_streamfile(sf_key);
return 0;
}
STREAMFILE* read_filemap_file(STREAMFILE* sf, int file_num) {
return read_filemap_file_pos(sf, file_num, NULL);
}
STREAMFILE* read_filemap_file_pos(STREAMFILE* sf, int file_num, int* p_pos) {
char filename[PATH_LIMIT];
off_t txt_offset, file_size;
STREAMFILE* sf_map = NULL;
int file_pos = 0;
sf_map = open_streamfile_by_filename(sf, ".txtm");
if (!sf_map) goto fail;
get_streamfile_filename(sf, filename, sizeof(filename));
txt_offset = read_bom(sf_map);
file_size = get_streamfile_size(sf_map);
/* read lines and find target filename, format is (filename): value1, ... valueN */
while (txt_offset < file_size) {
char line[0x2000];
char key[PATH_LIMIT] = { 0 }, val[0x2000] = { 0 };
int ok, bytes_read, line_ok;
bytes_read = read_line(line, sizeof(line), txt_offset, sf_map, &line_ok);
if (!line_ok) goto fail;
txt_offset += bytes_read;
/* get key/val (ignores lead/trailing spaces, stops at comment/separator) */
ok = sscanf(line, " %[^\t#:] : %[^\t#\r\n] ", key, val);
if (ok != 2) { /* ignore line if no key=val (comment or garbage) */
/* better way? */
if (strcmp(line, "#@reset-pos") == 0) {
file_pos = 0;
}
continue;
}
if (strcmp(key, filename) == 0) {
int n;
char subval[PATH_LIMIT];
const char* current = val;
int i;
for (i = 0; i <= file_num; i++) {
if (current[0] == '\0')
goto fail;
ok = sscanf(current, " %[^\t#\r\n,]%n ", subval, &n);
if (ok != 1)
goto fail;
if (i == file_num) {
if (p_pos) *p_pos = file_pos;
close_streamfile(sf_map);
return open_streamfile_by_filename(sf, subval);
}
current += n;
if (current[0] == ',')
current++;
}
}
file_pos++;
}
fail:
close_streamfile(sf_map);
return NULL;
}
void fix_dir_separators(char* filename) {
char c;
int i = 0;
while ((c = filename[i]) != '\0') {
if ((c == '\\' && DIR_SEPARATOR == '/') || (c == '/' && DIR_SEPARATOR == '\\'))
filename[i] = DIR_SEPARATOR;
i++;
}
}
/* ************************************************************************* */
int check_extensions(STREAMFILE* sf, const char* cmp_exts) {
char filename[PATH_LIMIT];
const char* ext = NULL;
@ -1393,73 +1229,6 @@ int check_extensions(STREAMFILE* sf, const char* cmp_exts) {
/* ************************************************************************* */
/**
* Find a chunk starting from an offset, and save its offset/size (if not NULL), with offset after id/size.
* Works for chunked headers in the form of "chunk_id chunk_size (data)"xN (ex. RIFF).
* The start_offset should be the first actual chunk (not "RIFF" or "WAVE" but "fmt ").
* "full_chunk_size" signals chunk_size includes 4+4+data.
*
* returns 0 on failure
*/
static int find_chunk_internal(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, size_t max_size, int full_chunk_size, off_t *out_chunk_offset, size_t *out_chunk_size, int big_endian_type, int big_endian_size, int zero_size_end) {
int32_t (*read_32bit_type)(off_t,STREAMFILE*) = big_endian_type ? read_32bitBE : read_32bitLE;
int32_t (*read_32bit_size)(off_t,STREAMFILE*) = big_endian_size ? read_32bitBE : read_32bitLE;
off_t offset, max_offset;
size_t file_size = get_streamfile_size(sf);
if (max_size == 0)
max_size = file_size;
offset = start_offset;
max_offset = offset + max_size;
if (max_offset > file_size)
max_offset = file_size;
/* read chunks */
while (offset < max_offset) {
uint32_t chunk_type = read_32bit_type(offset + 0x00,sf);
uint32_t chunk_size = read_32bit_size(offset + 0x04,sf);
if (chunk_type == 0xFFFFFFFF || chunk_size == 0xFFFFFFFF)
return 0;
if (chunk_type == chunk_id) {
if (out_chunk_offset) *out_chunk_offset = offset + 0x08;
if (out_chunk_size) *out_chunk_size = chunk_size;
return 1;
}
/* empty chunk with 0 size, seen in some formats (XVAG uses it as end marker, Wwise doesn't) */
if (chunk_size == 0 && zero_size_end)
return 0;
offset += full_chunk_size ? chunk_size : 0x08 + chunk_size;
}
return 0;
}
int find_chunk_be(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, int full_chunk_size, off_t *out_chunk_offset, size_t *out_chunk_size) {
return find_chunk(sf, chunk_id, start_offset, full_chunk_size, out_chunk_offset, out_chunk_size, 1, 0);
}
int find_chunk_le(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, int full_chunk_size, off_t *out_chunk_offset, size_t *out_chunk_size) {
return find_chunk(sf, chunk_id, start_offset, full_chunk_size, out_chunk_offset, out_chunk_size, 0, 0);
}
int find_chunk(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, int full_chunk_size, off_t *out_chunk_offset, size_t *out_chunk_size, int big_endian_size, int zero_size_end) {
return find_chunk_internal(sf, chunk_id, start_offset, 0, full_chunk_size, out_chunk_offset, out_chunk_size, 1, big_endian_size, zero_size_end);
}
int find_chunk_riff_le(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, size_t max_size, off_t *out_chunk_offset, size_t *out_chunk_size) {
return find_chunk_internal(sf, chunk_id, start_offset, max_size, 0, out_chunk_offset, out_chunk_size, 1, 0, 0);
}
int find_chunk_riff_be(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, size_t max_size, off_t *out_chunk_offset, size_t *out_chunk_size) {
return find_chunk_internal(sf, chunk_id, start_offset, max_size, 0, out_chunk_offset, out_chunk_size, 1, 1, 0);
}
int find_chunk_riff_ve(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, size_t max_size, off_t *out_chunk_offset, size_t *out_chunk_size, int big_endian) {
return find_chunk_internal(sf, chunk_id, start_offset, max_size, 0, out_chunk_offset, out_chunk_size, big_endian, big_endian, 0);
}
/* ************************************************************************* */
/* copies name as-is (may include full path included) */
void get_streamfile_name(STREAMFILE* sf, char* buffer, size_t size) {
sf->get_name(sf, buffer, size);

View File

@ -178,34 +178,11 @@ size_t read_string_utf16(char* buf, size_t buf_size, off_t offset, STREAMFILE* s
size_t read_string_utf16le(char* buf, size_t buf_size, off_t offset, STREAMFILE* sf);
size_t read_string_utf16be(char* buf, size_t buf_size, off_t offset, STREAMFILE* sf);
/* Opens a file containing decryption keys and copies to buffer.
* Tries "(name.ext)key" (per song), "(.ext)key" (per folder) keynames.
* returns size of key if found and copied */
size_t read_key_file(uint8_t* buf, size_t buf_size, STREAMFILE* sf);
/* Opens .txtm file containing file:companion file(-s) mappings and tries to see if there's a match
* then loads the associated companion file if one is found */
STREAMFILE* read_filemap_file(STREAMFILE *sf, int file_num);
STREAMFILE* read_filemap_file_pos(STREAMFILE *sf, int file_num, int* p_pos);
/* hack to allow relative paths in various OSs */
void fix_dir_separators(char* filename);
/* Checks if the stream filename is one of the extensions (comma-separated, ex. "adx" or "adx,aix").
* Empty is ok to accept files without extension ("", "adx,,aix"). Returns 0 on failure */
int check_extensions(STREAMFILE* sf, const char* cmp_exts);
/* chunk-style file helpers */
int find_chunk_be(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, int full_chunk_size, off_t* p_chunk_offset, size_t* p_chunk_size);
int find_chunk_le(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, int full_chunk_size, off_t* p_chunk_offset, size_t* p_chunk_size);
int find_chunk(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, int full_chunk_size, off_t* p_chunk_offset, size_t* p_chunk_size, int big_endian_size, int zero_size_end);
/* find a RIFF-style chunk (with chunk_size not including id and size) */
int find_chunk_riff_le(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, size_t max_size, off_t* p_chunk_offset, size_t* p_chunk_size);
int find_chunk_riff_be(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, size_t max_size, off_t* p_chunk_offset, size_t* p_chunk_size);
/* same with chunk ids in variable endianess (so instead of "fmt " has " tmf" */
int find_chunk_riff_ve(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, size_t max_size, off_t* p_chunk_offset, size_t* p_chunk_size, int big_endian);
/* filename helpers */
void get_streamfile_name(STREAMFILE* sf, char* buf, size_t size);
void get_streamfile_filename(STREAMFILE* sf, char* buf, size_t size);

View File

@ -33,3 +33,71 @@ int next_chunk(chunk_t* chunk, STREAMFILE* sf) {
/* more chunks remain */
return 1;
}
/* ************************************************************************* */
/**
* Find a chunk starting from an offset, and save its offset/size (if not NULL), with offset after id/size.
* Works for chunked headers in the form of "chunk_id chunk_size (data)"xN (ex. RIFF).
* The start_offset should be the first actual chunk (not "RIFF" or "WAVE" but "fmt ").
* "full_chunk_size" signals chunk_size includes 4+4+data.
*
* returns 0 on failure
*/
static int find_chunk_internal(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, size_t max_size, int full_chunk_size, off_t *out_chunk_offset, size_t *out_chunk_size, int big_endian_type, int big_endian_size, int zero_size_end) {
int32_t (*read_32bit_type)(off_t,STREAMFILE*) = big_endian_type ? read_32bitBE : read_32bitLE;
int32_t (*read_32bit_size)(off_t,STREAMFILE*) = big_endian_size ? read_32bitBE : read_32bitLE;
off_t offset, max_offset;
size_t file_size = get_streamfile_size(sf);
if (max_size == 0)
max_size = file_size;
offset = start_offset;
max_offset = offset + max_size;
if (max_offset > file_size)
max_offset = file_size;
/* read chunks */
while (offset < max_offset) {
uint32_t chunk_type = read_32bit_type(offset + 0x00,sf);
uint32_t chunk_size = read_32bit_size(offset + 0x04,sf);
if (chunk_type == 0xFFFFFFFF || chunk_size == 0xFFFFFFFF)
return 0;
if (chunk_type == chunk_id) {
if (out_chunk_offset) *out_chunk_offset = offset + 0x08;
if (out_chunk_size) *out_chunk_size = chunk_size;
return 1;
}
/* empty chunk with 0 size, seen in some formats (XVAG uses it as end marker, Wwise doesn't) */
if (chunk_size == 0 && zero_size_end)
return 0;
offset += full_chunk_size ? chunk_size : 0x08 + chunk_size;
}
return 0;
}
int find_chunk_be(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, int full_chunk_size, off_t *out_chunk_offset, size_t *out_chunk_size) {
return find_chunk(sf, chunk_id, start_offset, full_chunk_size, out_chunk_offset, out_chunk_size, 1, 0);
}
int find_chunk_le(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, int full_chunk_size, off_t *out_chunk_offset, size_t *out_chunk_size) {
return find_chunk(sf, chunk_id, start_offset, full_chunk_size, out_chunk_offset, out_chunk_size, 0, 0);
}
int find_chunk(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, int full_chunk_size, off_t *out_chunk_offset, size_t *out_chunk_size, int big_endian_size, int zero_size_end) {
return find_chunk_internal(sf, chunk_id, start_offset, 0, full_chunk_size, out_chunk_offset, out_chunk_size, 1, big_endian_size, zero_size_end);
}
int find_chunk_riff_le(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, size_t max_size, off_t *out_chunk_offset, size_t *out_chunk_size) {
return find_chunk_internal(sf, chunk_id, start_offset, max_size, 0, out_chunk_offset, out_chunk_size, 1, 0, 0);
}
int find_chunk_riff_be(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, size_t max_size, off_t *out_chunk_offset, size_t *out_chunk_size) {
return find_chunk_internal(sf, chunk_id, start_offset, max_size, 0, out_chunk_offset, out_chunk_size, 1, 1, 0);
}
int find_chunk_riff_ve(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, size_t max_size, off_t *out_chunk_offset, size_t *out_chunk_size, int big_endian) {
return find_chunk_internal(sf, chunk_id, start_offset, max_size, 0, out_chunk_offset, out_chunk_size, big_endian, big_endian, 0);
}

View File

@ -26,4 +26,16 @@ enum {
};
#endif
/* chunk-style file helpers (the above is more performant, this is mainly for quick checks) */
int find_chunk_be(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, int full_chunk_size, off_t* p_chunk_offset, size_t* p_chunk_size);
int find_chunk_le(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, int full_chunk_size, off_t* p_chunk_offset, size_t* p_chunk_size);
int find_chunk(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, int full_chunk_size, off_t* p_chunk_offset, size_t* p_chunk_size, int big_endian_size, int zero_size_end);
/* find a RIFF-style chunk (with chunk_size not including id and size) */
int find_chunk_riff_le(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, size_t max_size, off_t* p_chunk_offset, size_t* p_chunk_size);
int find_chunk_riff_be(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, size_t max_size, off_t* p_chunk_offset, size_t* p_chunk_size);
/* same with chunk ids in variable endianess (so instead of "fmt " has " tmf" */
int find_chunk_riff_ve(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, size_t max_size, off_t* p_chunk_offset, size_t* p_chunk_size, int big_endian);
#endif

148
src/util/companion_files.c Normal file
View File

@ -0,0 +1,148 @@
#include "companion_files.h"
#include "paths.h"
#include "../vgmstream.h"
size_t read_key_file(uint8_t* buf, size_t buf_size, STREAMFILE* sf) {
char keyname[PATH_LIMIT];
char filename[PATH_LIMIT];
const char *path, *ext;
STREAMFILE* sf_key = NULL;
size_t keysize;
get_streamfile_name(sf, filename, sizeof(filename));
if (strlen(filename)+4 > sizeof(keyname)) goto fail;
/* try to open a keyfile using variations */
{
ext = strrchr(filename,'.');
if (ext!=NULL) ext = ext+1;
path = strrchr(filename, DIR_SEPARATOR);
if (path!=NULL) path = path+1;
/* "(name.ext)key" */
strcpy(keyname, filename);
strcat(keyname, "key");
sf_key = sf->open(sf, keyname, STREAMFILE_DEFAULT_BUFFER_SIZE);
if (sf_key) goto found;
/* "(name.ext)KEY" */
/*
strcpy(keyname+strlen(keyname)-3,"KEY");
sf_key = sf->open(sf, keyname, STREAMFILE_DEFAULT_BUFFER_SIZE);
if (sf_key) goto found;
*/
/* "(.ext)key" */
if (path) {
strcpy(keyname, filename);
keyname[path-filename] = '\0';
strcat(keyname, ".");
} else {
strcpy(keyname, ".");
}
if (ext) strcat(keyname, ext);
strcat(keyname, "key");
sf_key = sf->open(sf, keyname, STREAMFILE_DEFAULT_BUFFER_SIZE);
if (sf_key) goto found;
/* "(.ext)KEY" */
/*
strcpy(keyname+strlen(keyname)-3,"KEY");
sf_key = sf->open(sf, keyname, STREAMFILE_DEFAULT_BUFFER_SIZE);
if (sf_key) goto found;
*/
goto fail;
}
found:
keysize = get_streamfile_size(sf_key);
if (keysize > buf_size) goto fail;
if (read_streamfile(buf, 0, keysize, sf_key) != keysize)
goto fail;
close_streamfile(sf_key);
return keysize;
fail:
close_streamfile(sf_key);
return 0;
}
STREAMFILE* read_filemap_file(STREAMFILE* sf, int file_num) {
return read_filemap_file_pos(sf, file_num, NULL);
}
STREAMFILE* read_filemap_file_pos(STREAMFILE* sf, int file_num, int* p_pos) {
char filename[PATH_LIMIT];
off_t txt_offset, file_size;
STREAMFILE* sf_map = NULL;
int file_pos = 0;
sf_map = open_streamfile_by_filename(sf, ".txtm");
if (!sf_map) goto fail;
get_streamfile_filename(sf, filename, sizeof(filename));
txt_offset = read_bom(sf_map);
file_size = get_streamfile_size(sf_map);
/* read lines and find target filename, format is (filename): value1, ... valueN */
while (txt_offset < file_size) {
char line[0x2000];
char key[PATH_LIMIT] = { 0 }, val[0x2000] = { 0 };
int ok, bytes_read, line_ok;
bytes_read = read_line(line, sizeof(line), txt_offset, sf_map, &line_ok);
if (!line_ok) goto fail;
txt_offset += bytes_read;
/* get key/val (ignores lead/trailing spaces, stops at comment/separator) */
ok = sscanf(line, " %[^\t#:] : %[^\t#\r\n] ", key, val);
if (ok != 2) { /* ignore line if no key=val (comment or garbage) */
/* better way? */
if (strcmp(line, "#@reset-pos") == 0) {
file_pos = 0;
}
continue;
}
if (strcmp(key, filename) == 0) {
int n;
char subval[PATH_LIMIT];
const char* current = val;
int i;
for (i = 0; i <= file_num; i++) {
if (current[0] == '\0')
goto fail;
ok = sscanf(current, " %[^\t#\r\n,]%n ", subval, &n);
if (ok != 1)
goto fail;
if (i == file_num) {
if (p_pos) *p_pos = file_pos;
close_streamfile(sf_map);
return open_streamfile_by_filename(sf, subval);
}
current += n;
if (current[0] == ',')
current++;
}
}
file_pos++;
}
fail:
close_streamfile(sf_map);
return NULL;
}

View File

@ -0,0 +1,16 @@
#ifndef _COMPANION_FILES_H
#define _COMPANION_FILES_H
#include "../streamfile.h"
/* Opens a file containing decryption keys and copies to buffer.
* Tries "(name.ext)key" (per song), "(.ext)key" (per folder) keynames.
* returns size of key if found and copied */
size_t read_key_file(uint8_t* buf, size_t buf_size, STREAMFILE* sf);
/* Opens .txtm file containing file:companion file(-s) mappings and tries to see if there's a match
* then loads the associated companion file if one is found */
STREAMFILE* read_filemap_file(STREAMFILE *sf, int file_num);
STREAMFILE* read_filemap_file_pos(STREAMFILE *sf, int file_num, int* p_pos);
#endif

11
src/util/paths.c Normal file
View File

@ -0,0 +1,11 @@
#include "paths.h"
void fix_dir_separators(char* filename) {
char c;
int i = 0;
while ((c = filename[i]) != '\0') {
if ((c == '\\' && DIR_SEPARATOR == '/') || (c == '/' && DIR_SEPARATOR == '\\'))
filename[i] = DIR_SEPARATOR;
i++;
}
}

17
src/util/paths.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef _PATHS_H
#define _PATHS_H
#ifndef DIR_SEPARATOR
#if defined (_WIN32) || defined (WIN32)
#define DIR_SEPARATOR '\\'
#else
#define DIR_SEPARATOR '/'
#endif
#endif
/* hack to allow relative paths in various OSs */
void fix_dir_separators(char* filename);
//const char* filename_extension(const char* pathname);
#endif