From 6805937d1b786e469c51db6866a67782b8acb3ec Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 14 Jul 2024 20:24:53 +0200 Subject: [PATCH] cleanup: misc doc/fixes --- audacious/plugin.cc | 1 + cli/vgmstream_cli.c | 4 +- src/coding/libs/clhca.h | 26 ++++---- src/formats.c | 48 ++++++++------- src/layout/blocked_caf.c | 29 ++++++--- src/meta/caf.c | 128 ++++++++++++++++++++------------------- src/meta/vpk.c | 36 ++++++----- src/meta/xwb.c | 19 +++--- src/streamfile.c | 7 ++- src/util/text_reader.h | 86 +++++++++++++------------- 10 files changed, 203 insertions(+), 181 deletions(-) diff --git a/audacious/plugin.cc b/audacious/plugin.cc index 95383583..74a63c0a 100644 --- a/audacious/plugin.cc +++ b/audacious/plugin.cc @@ -442,6 +442,7 @@ bool VgmstreamPlugin::play(const char * filename, VFSFile & file) { render_vgmstream(buffer, to_do, vgmstream); write_audio(buffer, to_do * sizeof(short) * output_channels); + //TODO: detect how many written decode_pos_samples += to_do; } diff --git a/cli/vgmstream_cli.c b/cli/vgmstream_cli.c index a8c35748..f5ed813d 100644 --- a/cli/vgmstream_cli.c +++ b/cli/vgmstream_cli.c @@ -901,7 +901,7 @@ static int write_file(VGMSTREAM* vgmstream, cli_config* cfg) { render_vgmstream(buf, to_get, vgmstream); - swap_samples_le(buf, channels * to_get); /* write PC endian */ + swap_samples_le(buf, channels * to_get); /* change to WAV (LE) endian if PC is Big Endian */ fwrite(buf, sizeof(sample_t), to_get * channels, outfile); /* should write infinitely until program kill */ } @@ -929,7 +929,7 @@ static int write_file(VGMSTREAM* vgmstream, cli_config* cfg) { render_vgmstream(buf, to_get, vgmstream); if (!cfg->decode_only) { - swap_samples_le(buf, channels * to_get); /* write PC endian */ + swap_samples_le(buf, channels * to_get); /* change to WAV (LE) endian if PC is Big Endian */ fwrite(buf, sizeof(sample_t), to_get * channels, outfile); } } diff --git a/src/coding/libs/clhca.h b/src/coding/libs/clhca.h index 60cba319..84b4aae0 100644 --- a/src/coding/libs/clhca.h +++ b/src/coding/libs/clhca.h @@ -4,26 +4,26 @@ /* Must pass at least 8 bytes of data to this function. * Returns <0 on non-match, or header size on success. */ -int clHCA_isOurFile(const void *data, unsigned int size); +int clHCA_isOurFile(const void* data, unsigned int size); /* The opaque state structure. */ typedef struct clHCA clHCA; /* In case you wish to allocate and reset the structure on your own. */ int clHCA_sizeof(void); -void clHCA_clear(clHCA *); -void clHCA_done(clHCA *); +void clHCA_clear(clHCA* hca); +void clHCA_done(clHCA* hca); /* Or you could let the library allocate it. */ -clHCA * clHCA_new(void); -void clHCA_delete(clHCA *); +clHCA* clHCA_new(void); +void clHCA_delete(clHCA* hca); /* Parses the HCA header. Must be called before any decoding may be performed, * and size must be at least headerSize long. The recommended way is to detect * the header length with clHCA_isOurFile, then read data and call this. * May be called multiple times to reset decoder state. * Returns 0 on success, <0 on failure. */ -int clHCA_DecodeHeader(clHCA *, const void *data, unsigned int size); +int clHCA_DecodeHeader(clHCA* hca, const void* data, unsigned int size); typedef struct clHCA_stInfo { unsigned int version; @@ -40,7 +40,7 @@ typedef struct clHCA_stInfo { unsigned int loopStartDelay; /* samples in block before loop starts */ unsigned int loopEndPadding; /* samples in block after loop ends */ unsigned int samplesPerBlock; /* should be 1024 */ - const char *comment; + const char* comment; unsigned int encryptionEnabled; /* requires keycode */ /* Derived sample formulas: @@ -53,33 +53,33 @@ typedef struct clHCA_stInfo { /* Retrieves header information for decoding and playback (it's the caller's responsability * to apply looping, encoder delay/skip samples, etc). May be called after clHCA_DecodeHeader. * Returns 0 on success, <0 on failure. */ -int clHCA_getInfo(clHCA *, clHCA_stInfo *out); +int clHCA_getInfo(clHCA* hca, clHCA_stInfo* out); /* Decodes a single frame, from data after headerSize. Should be called after * clHCA_DecodeHeader and size must be at least blockSize long. * Data may be modified if encrypted. * Returns 0 on success, <0 on failure. */ -int clHCA_DecodeBlock(clHCA *, void *data, unsigned int size); +int clHCA_DecodeBlock(clHCA* hca, void* data, unsigned int size); /* Extracts signed and clipped 16 bit samples into sample buffer. * May be called after clHCA_DecodeBlock, and will return the same data until * next decode. Buffer must be at least (samplesPerBlock*channels) long. */ -void clHCA_ReadSamples16(clHCA *, signed short * outSamples); +void clHCA_ReadSamples16(clHCA* hca, short* outSamples); /* Sets a 64 bit encryption key, to properly decode blocks. This may be called * multiple times to change the key, before or after clHCA_DecodeHeader. * Key is ignored if the file is not encrypted. */ -void clHCA_SetKey(clHCA *, unsigned long long keycode); +void clHCA_SetKey(clHCA* hca, unsigned long long keycode); /* Tests a single frame for validity, mainly to test if current key is correct. * Returns <0 on incorrect block (wrong key), 0 on silent block (not useful to determine) * and >0 if block is correct (the closer to 1 the more likely). * Incorrect keys may give a few valid frames, so it's best to test a number of them * and select the key with scores closer to 1. */ -int clHCA_TestBlock(clHCA *hca, void *data, unsigned int size); +int clHCA_TestBlock(clHCA* hca, void* data, unsigned int size); /* Resets the internal decode state, used when restarting to decode the file from the beginning. * Without it there are minor differences, mainly useful when testing a new key. */ -void clHCA_DecodeReset(clHCA * hca); +void clHCA_DecodeReset(clHCA* hca); #endif diff --git a/src/formats.c b/src/formats.c index 4dcaf714..f201257e 100644 --- a/src/formats.c +++ b/src/formats.c @@ -734,12 +734,18 @@ static const char* common_extension_list[] = { /* List supported formats and return elements in the list, for plugins that need to know. */ -const char ** vgmstream_get_formats(size_t * size) { +const char** vgmstream_get_formats(size_t* size) { + if (!size) + return NULL; + *size = sizeof(extension_list) / sizeof(char*); return extension_list; } -const char ** vgmstream_get_common_formats(size_t * size) { +const char** vgmstream_get_common_formats(size_t* size) { + if (!size) + return NULL; + *size = sizeof(common_extension_list) / sizeof(char*); return common_extension_list; } @@ -766,18 +772,18 @@ typedef struct { static const coding_info coding_info_list[] = { {coding_SILENCE, "Silence"}, - {coding_PCM16LE, "Little Endian 16-bit PCM"}, - {coding_PCM16BE, "Big Endian 16-bit PCM"}, - {coding_PCM16_int, "16-bit PCM with 2 byte interleave (block)"}, + {coding_PCM16LE, "16-bit Little Endian PCM"}, + {coding_PCM16BE, "16-bit Big Endian PCM"}, + {coding_PCM16_int, "16-bit PCM (block)"}, {coding_PCM8, "8-bit signed PCM"}, - {coding_PCM8_int, "8-bit signed PCM with 1 byte interleave (block)"}, + {coding_PCM8_int, "8-bit signed PCM (block)"}, {coding_PCM8_U, "8-bit unsigned PCM"}, - {coding_PCM8_U_int, "8-bit unsigned PCM with 1 byte interleave (block)"}, - {coding_PCM8_SB, "8-bit PCM with sign bit"}, + {coding_PCM8_U_int, "8-bit unsigned PCM (block)"}, + {coding_PCM8_SB, "8-bit sign bit PCM"}, {coding_PCM4, "4-bit signed PCM"}, {coding_PCM4_U, "4-bit unsigned PCM"}, {coding_ULAW, "8-bit u-Law"}, - {coding_ULAW_int, "8-bit u-Law with 1 byte interleave (block)"}, + {coding_ULAW_int, "8-bit u-Law (block)"}, {coding_ALAW, "8-bit a-Law"}, {coding_PCMFLOAT, "32-bit float PCM"}, {coding_PCM24LE, "24-bit Little Endian PCM"}, @@ -876,9 +882,9 @@ static const coding_info coding_info_list[] = { {coding_COMPRESSWAVE, "CompressWave Huffman ADPCM"}, {coding_SDX2, "Squareroot-delta-exact (SDX2) 8-bit DPCM"}, - {coding_SDX2_int, "Squareroot-delta-exact (SDX2) 8-bit DPCM with 1 byte interleave"}, + {coding_SDX2_int, "Squareroot-delta-exact (SDX2) 8-bit DPCM (block)"}, {coding_CBD2, "Cuberoot-delta-exact (CBD2) 8-bit DPCM"}, - {coding_CBD2_int, "Cuberoot-delta-exact (CBD2) 8-bit DPCM with 1 byte interleave"}, + {coding_CBD2_int, "Cuberoot-delta-exact (CBD2) 8-bit DPCM (block)"}, {coding_SASSC, "Activision / EXAKT SASSC 8-bit DPCM"}, {coding_DERF, "Xilam DERF 8-bit DPCM"}, {coding_WADY, "Marble WADY 8-bit DPCM"}, @@ -1010,7 +1016,7 @@ static const meta_info meta_info_list[] = { {meta_XA, "Sony XA header"}, {meta_RXWS, "Sony RXWS header"}, {meta_RAW_INT, "PS2 .int raw header"}, - {meta_OMU, "Outrage OMU Header"}, + {meta_OMU, "Outrage OMU header"}, {meta_DSP_STM, "Intelligent Systems STM header"}, {meta_EXST, "Sony EXST header"}, {meta_SVAG_KCET, "Konami SVAG header"}, @@ -1035,8 +1041,8 @@ static const meta_info meta_info_list[] = { {meta_DSP_STR, "Cauldron .STR header"}, {meta_EA_SCHL, "Electronic Arts SCHl header"}, {meta_EA_SCHL_fixed, "Electronic Arts SCHl header (fixed)"}, - {meta_CAF, "tri-Crescendo CAF Header"}, - {meta_VPK, "SCE America VPK Header"}, + {meta_CAF, "tri-Crescendo CAF header"}, + {meta_VPK, "SCE America VPK header"}, {meta_GENH, "GENH generic header"}, {meta_DSP_SADB, "Procyon Studio SADB header"}, {meta_SADL, "Procyon Studio SADL header"}, @@ -1055,7 +1061,7 @@ static const meta_info meta_info_list[] = { {meta_NWA_GAMEEXEINI, "VisualArt's NWA header (Gameexe.ini looping)"}, {meta_XSS, "Dino Crisis 3 XSS File"}, {meta_HGC1, "Cauldron HGC1 header"}, - {meta_AUS, "Capcom AUS Header"}, + {meta_AUS, "Atomic Planet AUS header"}, {meta_RWS, "RenderWare RWS header"}, {meta_EA_1SNH, "Electronic Arts 1SNh header"}, {meta_EA_EACS, "Electronic Arts EACS header"}, @@ -1070,17 +1076,17 @@ static const meta_info meta_info_list[] = { {meta_PS2_XA30, "Reflections XA30 PS2 header"}, {meta_MUSC, "Krome MUSC header"}, {meta_MUSX, "Eurocom MUSX header"}, - {meta_FILP, "cavia FILp Header"}, + {meta_FILP, "cavia FILp header"}, {meta_IKM, "MiCROViSiON IKM header"}, {meta_STER, "ALCHEMY STER header"}, {meta_SAT_DVI, "Konami DVI. header"}, {meta_DC_KCEY, "Konami KCEY header"}, {meta_BG00, "Cave BG00 header"}, - {meta_RSTM_ROCKSTAR, "Rockstar Games RSTM Header"}, - {meta_ACM, "InterPlay ACM Header"}, + {meta_RSTM_ROCKSTAR, "Rockstar Games RSTM header"}, + {meta_ACM, "InterPlay ACM header"}, {meta_MUS_ACM, "InterPlay MUS ACM header"}, - {meta_VIG_KCES, "Konami .VIG Header"}, - {meta_HXD, "Tecmo HXD Header"}, + {meta_VIG_KCES, "Konami .VIG header"}, + {meta_HXD, "Tecmo HXD header"}, {meta_VSV, "Square Enix .vsv Header"}, {meta_RIFF_WAVE_labl, "RIFF WAVE header (labl looping)"}, {meta_RIFF_WAVE_smpl, "RIFF WAVE header (smpl looping)"}, @@ -1101,7 +1107,7 @@ static const meta_info meta_info_list[] = { {meta_STR_SEGA_custom, "Sega Stream Asset Builder header (custom)"}, {meta_XMU, "Outrage XMU header"}, {meta_XVAS, "Konami .XVAS header"}, - {meta_XA2_ACCLAIM, "Acclaim .XA2 Header"}, + {meta_XA2_ACCLAIM, "Acclaim .XA2 header"}, {meta_SAP, "VING .SAP header"}, {meta_DC_IDVI, "Capcom IDVI header"}, {meta_KRAW, "Geometry Wars: Galaxies KRAW header"}, diff --git a/src/layout/blocked_caf.c b/src/layout/blocked_caf.c index 988e7714..6ed75747 100644 --- a/src/layout/blocked_caf.c +++ b/src/layout/blocked_caf.c @@ -2,20 +2,31 @@ #include "../vgmstream.h" /* each block is a new CAF header */ -void block_update_caf(off_t block_offset, VGMSTREAM * vgmstream) { - STREAMFILE* streamFile = vgmstream->ch[0].streamfile; - int i,ch; +void block_update_caf(off_t block_offset, VGMSTREAM* vgmstream) { + STREAMFILE* sf = vgmstream->ch[0].streamfile; + // 00: "CAF " + // 04: block size + // 08: block number + // 0c: empty + // 10: channel 1 offset + // 14: channel 1 size + // 18: channel 2 offset + // 1c: channel 2 size + // 20: loop start + // 24: loop end (same as last block) + // 28: DSP header stuff (repeated per block) + vgmstream->current_block_offset = block_offset; - vgmstream->next_block_offset = block_offset + read_32bitBE(block_offset+0x04, streamFile); - vgmstream->current_block_size = read_32bitBE(block_offset+0x14, streamFile); + vgmstream->next_block_offset = block_offset + read_u32be(block_offset + 0x04, sf); + vgmstream->current_block_size = read_u32be(block_offset + 0x14, sf); - for (ch = 0; ch < vgmstream->channels; ch++) { - vgmstream->ch[ch].offset = block_offset + read_32bitBE(block_offset+0x10+(0x08*ch), streamFile); + for (int ch = 0; ch < vgmstream->channels; ch++) { + vgmstream->ch[ch].offset = block_offset + read_u32be(block_offset + 0x10 + 0x08 * ch, sf); /* re-read coeffs (though blocks seem to repeat them) */ - for (i = 0; i < 16; i++) { - vgmstream->ch[ch].adpcm_coef[i] = read_16bitBE(block_offset+0x34 + 0x2c*ch + 0x02*i, streamFile); + for (int i = 0; i < 16; i++) { + vgmstream->ch[ch].adpcm_coef[i] = read_s16be(block_offset + 0x34 + 0x2c * ch + 0x02 * i, sf); } } } diff --git a/src/meta/caf.c b/src/meta/caf.c index ca1b1134..c337217d 100644 --- a/src/meta/caf.c +++ b/src/meta/caf.c @@ -1,62 +1,66 @@ -#include "meta.h" -#include "../layout/layout.h" -#include "../util.h" - -/* CAF - from tri-Crescendo games [Baten Kaitos 1/2 (GC), Fragile (Wii)] */ -VGMSTREAM * init_vgmstream_caf(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - off_t start_offset, offset; - size_t file_size; - int channel_count, loop_flag; - int32_t num_samples = 0; - uint32_t loop_start = -1; - - - /* checks */ - /* .caf: header id, .cfn: fake extension? , "" is accepted as files don't have extensions in the disc */ - if (!check_extensions(streamFile,"caf,cfn,")) - goto fail; - if (read_32bitBE(0x00,streamFile) != 0x43414620) /* "CAF " */ - goto fail; - - /* get total samples */ - offset = 0; - file_size = get_streamfile_size(streamFile); - while (offset < file_size) { - off_t next_block = read_32bitBE(offset+0x04,streamFile); - num_samples += read_32bitBE(offset+0x14,streamFile)/8*14; - - if(read_32bitBE(offset+0x20,streamFile)==read_32bitBE(offset+0x08,streamFile)) { - loop_start = num_samples - read_32bitBE(offset+0x14,streamFile)/8*14; - } - offset += next_block; - } - - start_offset = 0x00; - channel_count = 2; /* always stereo */ - loop_flag = (loop_start!=-1); - - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; - - vgmstream->sample_rate = 32000; - vgmstream->num_samples = num_samples; - if (loop_flag) { - vgmstream->loop_start_sample = loop_start; - vgmstream->loop_end_sample = num_samples; - } - - vgmstream->meta_type = meta_CAF; - vgmstream->coding_type = coding_NGC_DSP; - vgmstream->layout_type = layout_blocked_caf; - - if ( !vgmstream_open_stream(vgmstream,streamFile,start_offset) ) - goto fail; - return vgmstream; - -fail: - close_vgmstream(vgmstream); - return NULL; -} +#include "meta.h" +#include "../layout/layout.h" +#include "../coding/coding.h" + +/* CAF - from tri-Crescendo games [Baten Kaitos 1/2 (GC), Fragile (Wii)] */ +VGMSTREAM* init_vgmstream_caf(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; + off_t start_offset; + int channels, loop_flag; + int32_t num_samples = 0; + + + /* checks */ + if (!is_id32be(0x00,sf, "CAF ")) + return NULL; + + /* .caf: header id + * (extensionless): files on disc don't have any extensions + * .cfn: fake extension */ + if (!check_extensions(sf,"caf,cfn,")) + return NULL; + + /* get total samples from blocks + find loop */ //TODO reuse function calls + uint32_t loop_start = -1; + off_t offset = 0x00; + off_t file_size = get_streamfile_size(sf); + while (offset < file_size) { + // see blocked layout for block info + off_t next_block = read_u32be(offset+0x04,sf); + off_t channel_bytes = read_u32be(offset+0x14,sf); + int channel_samples = dsp_bytes_to_samples(channel_bytes, 1); + + if (read_u32be(offset+0x08,sf) == read_u32be(offset+0x20,sf) && loop_start < 0) { + loop_start = num_samples; + } + + num_samples += channel_samples; + offset += next_block; + } + + start_offset = 0x00; + channels = 2; /* always stereo */ + loop_flag = (loop_start != -1); + + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channels, loop_flag); + if (!vgmstream) goto fail; + + vgmstream->sample_rate = 32000; + vgmstream->num_samples = num_samples; + vgmstream->loop_start_sample = loop_start; + vgmstream->loop_end_sample = num_samples; + + vgmstream->meta_type = meta_CAF; + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->layout_type = layout_blocked_caf; + + if (!vgmstream_open_stream(vgmstream, sf, start_offset)) + goto fail; + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} diff --git a/src/meta/vpk.c b/src/meta/vpk.c index ddedd1cf..9f7750cb 100644 --- a/src/meta/vpk.c +++ b/src/meta/vpk.c @@ -2,49 +2,47 @@ #include "../coding/coding.h" /* VPK - from SCE America second party devs [God of War (PS2), NBA 08 (PS3)] */ -VGMSTREAM * init_vgmstream_vpk(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - int loop_flag, channel_count; +VGMSTREAM* init_vgmstream_vpk(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; + int loop_flag, channels; off_t start_offset, loop_channel_offset; - size_t channel_size; /* checks */ - if (!check_extensions(streamFile, "vpk")) - goto fail; - - if (read_32bitBE(0x00,streamFile) != 0x204B5056) /* " KPV" */ - goto fail; + if (!is_id32be(0x00,sf, " KPV")) + return NULL; + if (!check_extensions(sf, "vpk")) + return NULL; /* files are padded with garbage/silent 0xC00000..00 frames, and channel_size sometimes * has extra size into the padding: +0x10 (NBA08), +0x20 (GoW), or none (Sly 2, loops ok). * Could detect and remove to slightly improve full loops, but maybe this is just how the game works */ - channel_size = read_32bitLE(0x04,streamFile); + size_t channel_size = read_u32le(0x04,sf); - start_offset = read_32bitLE(0x08,streamFile); - channel_count = read_32bitLE(0x14,streamFile); + start_offset = read_u32le(0x08,sf); + channels = read_s32le(0x14,sf); /* 0x18+: channel config(?), 0x04 per channel */ - loop_channel_offset = read_32bitLE(0x7FC,streamFile); + loop_channel_offset = read_u32le(0x7FC,sf); loop_flag = (loop_channel_offset != 0); /* found in Sly 2/3 */ /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); + vgmstream = allocate_vgmstream(channels, loop_flag); if (!vgmstream) goto fail; - vgmstream->sample_rate = read_32bitLE(0x10,streamFile); - vgmstream->num_samples = ps_bytes_to_samples(channel_size*vgmstream->channels,vgmstream->channels); + vgmstream->sample_rate = read_s32le(0x10,sf); + vgmstream->num_samples = ps_bytes_to_samples(channel_size * channels, channels); if (vgmstream->loop_flag) { - vgmstream->loop_start_sample = ps_bytes_to_samples(loop_channel_offset*vgmstream->channels,vgmstream->channels); + vgmstream->loop_start_sample = ps_bytes_to_samples(loop_channel_offset * channels, channels); vgmstream->loop_end_sample = vgmstream->num_samples; } vgmstream->meta_type = meta_VPK; vgmstream->coding_type = coding_PSX; - vgmstream->interleave_block_size = read_32bitLE(0x0C,streamFile) / 2; /* even in >2ch */ + vgmstream->interleave_block_size = read_u32le(0x0C,sf) / 2; /* even in >2ch */ vgmstream->layout_type = layout_interleave; - if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) + if (!vgmstream_open_stream(vgmstream, sf, start_offset)) goto fail; return vgmstream; diff --git a/src/meta/xwb.c b/src/meta/xwb.c index 23448ff0..c2d40d7d 100644 --- a/src/meta/xwb.c +++ b/src/meta/xwb.c @@ -75,7 +75,7 @@ typedef struct { int fix_xma_loop_samples; } xwb_header; -static void get_name(char* buf, size_t maxsize, int target_subsong, xwb_header* xwb, STREAMFILE* sf); +static void get_name(char* buf, size_t buf_size, int target_subsong, xwb_header* xwb, STREAMFILE* sf); /* XWB - XACT Wave Bank (Microsoft SDK format for XBOX/XBOX360/Windows) */ @@ -638,10 +638,10 @@ fail: /* ****************************************************************************** */ -static int get_xwb_name(char* buf, size_t maxsize, int target_subsong, xwb_header* xwb, STREAMFILE* sf) { +static int get_xwb_name(char* buf, size_t buf_size, int target_subsong, xwb_header* xwb, STREAMFILE* sf) { size_t read; - if (!xwb->names_offset || !xwb->names_size || xwb->names_entry_size > maxsize) + if (!xwb->names_offset || !xwb->names_size || xwb->names_entry_size > buf_size) goto fail; read = read_string(buf,xwb->names_entry_size, xwb->names_offset + xwb->names_entry_size*(target_subsong-1),sf); @@ -653,7 +653,7 @@ fail: return 0; } -static int get_xsb_name(char* buf, size_t maxsize, int target_subsong, xwb_header* xwb, STREAMFILE* sf) { +static int get_xsb_name(char* buf, size_t buf_size, int target_subsong, xwb_header* xwb, STREAMFILE* sf) { xsb_header xsb = {0}; xsb.selected_stream = target_subsong - 1; @@ -670,8 +670,7 @@ static int get_xsb_name(char* buf, size_t maxsize, int target_subsong, xwb_heade if (!xsb.name_len || xsb.name[0] == '\0') goto fail; - strncpy(buf,xsb.name,maxsize); - buf[maxsize-1] = '\0'; + snprintf(buf, buf_size, "%s", xsb.name); return 1; fail: return 0; @@ -715,12 +714,12 @@ fail: return 0; } -static void get_name(char* buf, size_t maxsize, int target_subsong, xwb_header* xwb, STREAMFILE* sf_xwb) { +static void get_name(char* buf, size_t buf_size, int target_subsong, xwb_header* xwb, STREAMFILE* sf_xwb) { STREAMFILE* sf_name = NULL; int name_found; /* try to get the stream name in the .xwb, though they are very rarely included */ - name_found = get_xwb_name(buf, maxsize, target_subsong, xwb, sf_xwb); + name_found = get_xwb_name(buf, buf_size, target_subsong, xwb, sf_xwb); if (name_found) return; /* try again in a companion files */ @@ -730,7 +729,7 @@ static void get_name(char* buf, size_t maxsize, int target_subsong, xwb_header* sf_name = open_streamfile_by_ext(sf_xwb, "wbh"); if (!sf_name) goto fail; /* rarely found [Pac-Man World 2 (Xbox)] */ - name_found = get_wbh_name(buf, maxsize, target_subsong, xwb, sf_name); + name_found = get_wbh_name(buf, buf_size, target_subsong, xwb, sf_name); close_streamfile(sf_name); } else { @@ -738,7 +737,7 @@ static void get_name(char* buf, size_t maxsize, int target_subsong, xwb_header* sf_name = open_xsb_filename_pair(sf_xwb); if (!sf_name) goto fail; /* not all xwb have xsb though */ - name_found = get_xsb_name(buf, maxsize, target_subsong, xwb, sf_name); + name_found = get_xsb_name(buf, buf_size, target_subsong, xwb, sf_name); close_streamfile(sf_name); } diff --git a/src/streamfile.c b/src/streamfile.c index 6342ebe5..ec1febef 100644 --- a/src/streamfile.c +++ b/src/streamfile.c @@ -242,6 +242,9 @@ static STREAMFILE* open_stdio_streamfile_buffer_by_file(FILE* infile, const char uint8_t* buf = NULL; STDIO_STREAMFILE* this_sf = NULL; + if (buf_size <= 0) + buf_size = STREAMFILE_DEFAULT_BUFFER_SIZE; + buf = calloc(buf_size, sizeof(uint8_t)); if (!buf) goto fail; @@ -326,11 +329,11 @@ static STREAMFILE* open_stdio_streamfile_buffer(const char* const filename, size } STREAMFILE* open_stdio_streamfile(const char* filename) { - return open_stdio_streamfile_buffer(filename, STREAMFILE_DEFAULT_BUFFER_SIZE); + return open_stdio_streamfile_buffer(filename, 0); } STREAMFILE* open_stdio_streamfile_by_file(FILE* file, const char* filename) { - return open_stdio_streamfile_buffer_by_file(file, filename, STREAMFILE_DEFAULT_BUFFER_SIZE); + return open_stdio_streamfile_buffer_by_file(file, filename, 0); } /* **************************************************** */ diff --git a/src/util/text_reader.h b/src/util/text_reader.h index 93dc51ab..024d7242 100644 --- a/src/util/text_reader.h +++ b/src/util/text_reader.h @@ -1,43 +1,43 @@ -#ifndef _TEXT_READER_H_ -#define _TEXT_READER_H_ - - -/* Reader tuned for whole text files, reading chunks to minimize I/O with a single buffer. - * For short lines read_line may be more appropriate (reads up to line end, while this reads bigger chunks), - * which also allow \0 (this reader returns an error). - * NOTE: modifies passed buffer (lines are forced to end with \0 rather than \n). - * - * Usage: set text_reader_t and defaults with text_reader_init, call text_reader_get_line(...) to get lines. - * buf may be size+1 to allow 2^N chunk reads + trailing \0 (better performance?). - */ - -#include "../streamfile.h" - -typedef struct { - /* init */ - uint8_t* buf; /* where data will be read */ - int buf_size; /* size of the struct (also max line size) */ - STREAMFILE* sf; /* used to read data */ - uint32_t offset; /* sf pos */ - uint32_t max_offset; /* sf max */ - - /* internal */ - int filled; /* current buf bytes */ - int pos; /* current buf pos (last line) */ - int next_pos; /* buf pos on next call, after line end */ - int line_ok; /* current line is fully correct */ - - char* line; - int line_len; -} text_reader_t; - - -/* convenience function to init the above struct */ -int text_reader_init(text_reader_t* tr, uint8_t* buf, int buf_size, STREAMFILE* sf, uint32_t offset, uint32_t max); - -/* Reads and sets next line, or NULL if no lines are found (EOF). - * returns line length (0 for empty lines), or <0 if line was too long to store in buf. - * Will always return a valid (null terminated) string. */ -int text_reader_get_line(text_reader_t* tr, char** p_line); - -#endif +#ifndef _TEXT_READER_H_ +#define _TEXT_READER_H_ + + +/* Reader tuned for whole text files, reading chunks to minimize I/O with a single buffer. + * For short lines read_line may be more appropriate (reads up to line end, while this reads bigger chunks), + * which also allow \0 (this reader returns an error). + * NOTE: modifies passed buffer (lines are forced to end with \0 rather than \n). + * + * Usage: set text_reader_t and defaults with text_reader_init, call text_reader_get_line(...) to get lines. + * buf may be size+1 to allow 2^N chunk reads + trailing \0 (better performance?). + */ + +#include "../streamfile.h" + +typedef struct { + /* init */ + uint8_t* buf; /* where data will be read */ + int buf_size; /* size of the struct (also max line size) */ + STREAMFILE* sf; /* used to read data */ + uint32_t offset; /* sf pos */ + uint32_t max_offset; /* sf max */ + + /* internal */ + int filled; /* current buf bytes */ + int pos; /* current buf pos (last line) */ + int next_pos; /* buf pos on next call, after line end */ + int line_ok; /* current line is fully correct */ + + char* line; + int line_len; +} text_reader_t; + + +/* convenience function to init the above struct */ +int text_reader_init(text_reader_t* tr, uint8_t* buf, int buf_size, STREAMFILE* sf, uint32_t offset, uint32_t max); + +/* Reads and sets next line, or NULL if no lines are found (EOF). + * returns line length (0 for empty lines), or <0 if line was too long to store in buf. + * Will always return a valid (null terminated) string. */ +int text_reader_get_line(text_reader_t* tr, char** p_line); + +#endif