diff --git a/Frameworks/vgmstream/libvgmstream.xcodeproj/project.pbxproj b/Frameworks/vgmstream/libvgmstream.xcodeproj/project.pbxproj index 6c05eac08..a8d30b7f8 100644 --- a/Frameworks/vgmstream/libvgmstream.xcodeproj/project.pbxproj +++ b/Frameworks/vgmstream/libvgmstream.xcodeproj/project.pbxproj @@ -335,7 +335,6 @@ 836F6FBD18BDC2190095E648 /* nwa.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E8118BDC2180095E648 /* nwa.c */; }; 836F6FBF18BDC2190095E648 /* otm.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E8318BDC2180095E648 /* otm.c */; }; 836F6FC018BDC2190095E648 /* p3d.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E8418BDC2180095E648 /* p3d.c */; }; - 836F6FC118BDC2190095E648 /* pc_adp.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E8518BDC2180095E648 /* pc_adp.c */; }; 836F6FC218BDC2190095E648 /* pc_mxst.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E8618BDC2180095E648 /* pc_mxst.c */; }; 836F6FC718BDC2190095E648 /* pona.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E8B18BDC2180095E648 /* pona.c */; }; 836F6FC818BDC2190095E648 /* pos.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E8C18BDC2180095E648 /* pos.c */; }; @@ -621,6 +620,11 @@ 83D2007F248DDB770048BD24 /* mups.c in Sources */ = {isa = PBXBuildFile; fileRef = 83D20077248DDB770048BD24 /* mups.c */; }; 83D20080248DDB770048BD24 /* sadf.c in Sources */ = {isa = PBXBuildFile; fileRef = 83D20078248DDB770048BD24 /* sadf.c */; }; 83D20081248DDB770048BD24 /* sadl.c in Sources */ = {isa = PBXBuildFile; fileRef = 83D20079248DDB770048BD24 /* sadl.c */; }; + 83D26A7A26E66D98001A9475 /* adp_bos.c in Sources */ = {isa = PBXBuildFile; fileRef = 83D26A7626E66D98001A9475 /* adp_bos.c */; }; + 83D26A8126E66DC2001A9475 /* log.c in Sources */ = {isa = PBXBuildFile; fileRef = 83D26A7D26E66DC2001A9475 /* log.c */; }; + 83D26A8226E66DC2001A9475 /* chunks.h in Headers */ = {isa = PBXBuildFile; fileRef = 83D26A7E26E66DC2001A9475 /* chunks.h */; }; + 83D26A8326E66DC2001A9475 /* log.h in Headers */ = {isa = PBXBuildFile; fileRef = 83D26A7F26E66DC2001A9475 /* log.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 83D26A8426E66DC2001A9475 /* chunks.c in Sources */ = {isa = PBXBuildFile; fileRef = 83D26A8026E66DC2001A9475 /* chunks.c */; }; 83D6772D2653A30B00252130 /* libcelt_0061.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 83D6763026539A7200252130 /* libcelt_0061.framework */; }; 83D6772E2653A31400252130 /* libcelt_0110.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 83D676BE26539F4F00252130 /* libcelt_0110.framework */; }; 83D6772F2653A32B00252130 /* libcelt_0061.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 83D6763026539A7200252130 /* libcelt_0061.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; @@ -1136,7 +1140,6 @@ 836F6E8118BDC2180095E648 /* nwa.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nwa.c; sourceTree = ""; }; 836F6E8318BDC2180095E648 /* otm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = otm.c; sourceTree = ""; }; 836F6E8418BDC2180095E648 /* p3d.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = p3d.c; sourceTree = ""; }; - 836F6E8518BDC2180095E648 /* pc_adp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pc_adp.c; sourceTree = ""; }; 836F6E8618BDC2180095E648 /* pc_mxst.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pc_mxst.c; sourceTree = ""; }; 836F6E8B18BDC2180095E648 /* pona.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pona.c; sourceTree = ""; }; 836F6E8C18BDC2180095E648 /* pos.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pos.c; sourceTree = ""; }; @@ -1421,6 +1424,11 @@ 83D20077248DDB770048BD24 /* mups.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mups.c; sourceTree = ""; }; 83D20078248DDB770048BD24 /* sadf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sadf.c; sourceTree = ""; }; 83D20079248DDB770048BD24 /* sadl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sadl.c; sourceTree = ""; }; + 83D26A7626E66D98001A9475 /* adp_bos.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = adp_bos.c; sourceTree = ""; }; + 83D26A7D26E66DC2001A9475 /* log.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = log.c; sourceTree = ""; }; + 83D26A7E26E66DC2001A9475 /* chunks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = chunks.h; sourceTree = ""; }; + 83D26A7F26E66DC2001A9475 /* log.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = log.h; sourceTree = ""; }; + 83D26A8026E66DC2001A9475 /* chunks.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = chunks.c; sourceTree = ""; }; 83D6762B26539A7100252130 /* libcelt_0061.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = libcelt_0061.xcodeproj; path = ../libcelt_0061/libcelt_0061/libcelt_0061.xcodeproj; sourceTree = ""; }; 83D676B926539F4E00252130 /* libcelt_0110.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = libcelt_0110.xcodeproj; path = ../libcelt_0110/libcelt_0110/libcelt_0110.xcodeproj; sourceTree = ""; }; 83D731381A74968900CA1366 /* g719.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = g719.xcodeproj; path = ../g719/g719.xcodeproj; sourceTree = ""; }; @@ -1581,6 +1589,7 @@ 836F6DDF18BDC2180095E648 /* coding */, 836F6DFF18BDC2180095E648 /* layout */, 836F6E2718BDC2180095E648 /* meta */, + 83D26A7C26E66DC2001A9475 /* util */, 83AA7F892519C076004C5298 /* decode.c */, 83AA7F862519C076004C5298 /* decode.h */, 83A3F0711E3AD8B900D6A794 /* formats.c */, @@ -1779,6 +1788,7 @@ 837CEAD623487E8300E62A4A /* acb.c */, 836F6E2B18BDC2180095E648 /* acm.c */, 83F2CCE125A5B41600F46FA8 /* acx.c */, + 83D26A7626E66D98001A9475 /* adp_bos.c */, 83AA7F7A2519C042004C5298 /* adp_konami.c */, 834FE0CF215C79E8000A5D3D /* adpcm_capcom.c */, 83852B0A2680247900378854 /* ads_midway.c */, @@ -1997,7 +2007,6 @@ 836F6E8318BDC2180095E648 /* otm.c */, 836F6E8418BDC2180095E648 /* p3d.c */, 8349A8FE1FE6257F00E26435 /* pc_adp_otns.c */, - 836F6E8518BDC2180095E648 /* pc_adp.c */, 8349A8F01FE6257C00E26435 /* pc_ast.c */, 836F6E8618BDC2180095E648 /* pc_mxst.c */, 8306B0D12098458F000302D4 /* pcm_sre.c */, @@ -2228,6 +2237,17 @@ path = meta; sourceTree = ""; }; + 83D26A7C26E66DC2001A9475 /* util */ = { + isa = PBXGroup; + children = ( + 83D26A8026E66DC2001A9475 /* chunks.c */, + 83D26A7E26E66DC2001A9475 /* chunks.h */, + 83D26A7D26E66DC2001A9475 /* log.c */, + 83D26A7F26E66DC2001A9475 /* log.h */, + ); + path = util; + sourceTree = ""; + }; 83D6762C26539A7200252130 /* Products */ = { isa = PBXGroup; children = ( @@ -2270,11 +2290,13 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 83D26A8226E66DC2001A9475 /* chunks.h in Headers */, 836F705518BDC2190095E648 /* streamtypes.h in Headers */, 836F6F3518BDC2190095E648 /* nwa_decoder.h in Headers */, 83031EC9243C50A800C3F3E0 /* circus_decoder_lzxpcm.h in Headers */, 8346D97A25BF838C00D1A8B0 /* idtech_streamfile.h in Headers */, 8346D98425BF83B300D1A8B0 /* coding_utils_samples.h in Headers */, + 83D26A8326E66DC2001A9475 /* log.h in Headers */, 83C7282222BC893D00678B4A /* mta2_streamfile.h in Headers */, 83AA7F802519C042004C5298 /* sab_streamfile.h in Headers */, 83A21F87201D8981000F04B9 /* fsb_keys.h in Headers */, @@ -2576,6 +2598,7 @@ 8373341723F60C7B00DE14DC /* g7221_decoder_aes.c in Sources */, 836F702018BDC2190095E648 /* rkv.c in Sources */, 834FE0F4215C79ED000A5D3D /* wsi.c in Sources */, + 83D26A7A26E66D98001A9475 /* adp_bos.c in Sources */, 836F703218BDC2190095E648 /* str_asr.c in Sources */, 837CEB0223487F2C00E62A4A /* raw_int.c in Sources */, 836F702818BDC2190095E648 /* sat_dvi.c in Sources */, @@ -2601,6 +2624,7 @@ 836F6FB618BDC2190095E648 /* ngc_sck_dsp.c in Sources */, 836F6F2818BDC2190095E648 /* ima_decoder.c in Sources */, 837CEB072348809400E62A4A /* seb.c in Sources */, + 83D26A8126E66DC2001A9475 /* log.c in Sources */, 8306B0DD20984590000302D4 /* waf.c in Sources */, 8306B0B320984552000302D4 /* blocked_thp.c in Sources */, 832BF80921E05135006F50F1 /* fag.c in Sources */, @@ -2760,7 +2784,6 @@ 836F6FF318BDC2190095E648 /* ps2_rstm.c in Sources */, 8373342923F60CDC00DE14DC /* deblock_streamfile.c in Sources */, 836F6F7918BDC2190095E648 /* dc_asd.c in Sources */, - 836F6FC118BDC2190095E648 /* pc_adp.c in Sources */, 836F703B18BDC2190095E648 /* vsf.c in Sources */, 836F6F8218BDC2190095E648 /* ea_schl.c in Sources */, 834FBCE826BBC7D00095647F /* tantalus_decoder.c in Sources */, @@ -2912,6 +2935,7 @@ 836F6FA418BDC2190095E648 /* nds_hwas.c in Sources */, 83A21F8A201D8982000F04B9 /* fsb_encrypted.c in Sources */, 8306B0B120984552000302D4 /* blocked_halpst.c in Sources */, + 83D26A8426E66DC2001A9475 /* chunks.c in Sources */, 836F6FD018BDC2190095E648 /* ps2_b1s.c in Sources */, 83AA5D181F6E2F600020821C /* mpeg_custom_utils_awc.c in Sources */, 83031ED1243C50DF00C3F3E0 /* encrypted.c in Sources */, diff --git a/Frameworks/vgmstream/vgmstream/src/coding/coding.h b/Frameworks/vgmstream/vgmstream/src/coding/coding.h index 5ea384f64..d003d7482 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/coding.h +++ b/Frameworks/vgmstream/vgmstream/src/coding/coding.h @@ -682,6 +682,6 @@ int mpc_get_samples(STREAMFILE* sf, off_t offset, int32_t* p_samples, int32_t* p /* helper to pass a wrapped, clamped, fake extension-ed, SF to another meta */ -STREAMFILE* setup_subfile_streamfile(STREAMFILE* sf, off_t subfile_offset, size_t subfile_size, const char* extension); +STREAMFILE* setup_subfile_streamfile(STREAMFILE* sf, offv_t subfile_offset, size_t subfile_size, const char* extension); #endif /*_CODING_H*/ diff --git a/Frameworks/vgmstream/vgmstream/src/coding/coding_utils.c b/Frameworks/vgmstream/vgmstream/src/coding/coding_utils.c index 275cf1d04..1252fb2dc 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/coding_utils.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/coding_utils.c @@ -1015,21 +1015,21 @@ size_t aac_get_samples(STREAMFILE* sf, off_t start_offset, size_t bytes) { /* variable-sized var reader */ static int mpc_get_size(uint8_t* header, int header_size, int pos, int32_t* p_size) { - uint8_t tmp; - int32_t size = 0; + uint8_t tmp; + int32_t size = 0; - do { + do { if (pos >= header_size) return pos; - tmp = header[pos]; - size = (size << 7) | (tmp & 0x7F); - pos++; - } + tmp = header[pos]; + size = (size << 7) | (tmp & 0x7F); + pos++; + } while((tmp & 0x80)); - *p_size = size; - return pos; + *p_size = size; + return pos; } int mpc_get_samples(STREAMFILE* sf, off_t offset, int32_t* p_samples, int32_t* p_delay) { @@ -1092,8 +1092,8 @@ fail: /* CUSTOM STREAMFILES */ /* ******************************************** */ -STREAMFILE* setup_subfile_streamfile(STREAMFILE* sf, off_t subfile_offset, size_t subfile_size, const char* extension) { - STREAMFILE *new_sf = NULL; +STREAMFILE* setup_subfile_streamfile(STREAMFILE* sf, offv_t subfile_offset, size_t subfile_size, const char* extension) { + STREAMFILE* new_sf = NULL; new_sf = open_wrap_streamfile(sf); new_sf = open_clamp_streamfile_f(new_sf, subfile_offset, subfile_size); diff --git a/Frameworks/vgmstream/vgmstream/src/coding/ea_mt_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/ea_mt_decoder.c index 26d76b9e0..b7b71b2a5 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/ea_mt_decoder.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/ea_mt_decoder.c @@ -115,9 +115,9 @@ void decode_ea_mt(VGMSTREAM* vgmstream, sample_t* outbuf, int channelspacing, in * notify the decoder when a new substream begins (even with looping disabled). */ if (ch_data->loop_sample > 0 && ch_data->samples_done == ch_data->loop_sample) { ch_data->samples_filled = 0; - ch_data->samples_discard = 0; + ch_data->samples_discard = 0; - /* offset is usually at loop_offset here, but not always (ex. loop_sample < 432) */ + /* offset is usually at loop_offset here, but not always (ex. loop_sample < 432) */ ch_data->offset = ch_data->loop_offset; utk_set_ptr(ctx, 0, 0); /* reset the buffer reader */ utk_reset(ctx); /* decoder init (all fields must be reset, for some edge cases) */ diff --git a/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder.c index ae17c0cf4..54b09ccaf 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder.c @@ -322,7 +322,7 @@ ffmpeg_codec_data* init_ffmpeg_header_offset_subsong(STREAMFILE* sf, uint8_t* he goto fail; if (size == 0 || start + size > get_streamfile_size(sf)) { - VGM_LOG("FFMPEG: wrong start+size found: %x + %x > %x \n", (uint32_t)start, (uint32_t)size, get_streamfile_size(sf)); + vgm_asserti(size != 0, "FFMPEG: wrong start+size found: %x + %x > %x \n", (uint32_t)start, (uint32_t)size, get_streamfile_size(sf)); size = get_streamfile_size(sf) - start; } diff --git a/Frameworks/vgmstream/vgmstream/src/coding/hca_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/hca_decoder.c index e807ec63f..d4183b62f 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/hca_decoder.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/hca_decoder.c @@ -72,7 +72,7 @@ fail: } void decode_hca(hca_codec_data* data, sample_t* outbuf, int32_t samples_to_do) { - int samples_done = 0; + int samples_done = 0; const unsigned int channels = data->info.channelCount; const unsigned int blockSize = data->info.blockSize; diff --git a/Frameworks/vgmstream/vgmstream/src/coding/hca_decoder_clhca.h b/Frameworks/vgmstream/vgmstream/src/coding/hca_decoder_clhca.h index dc72d39a8..16089ce43 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/hca_decoder_clhca.h +++ b/Frameworks/vgmstream/vgmstream/src/coding/hca_decoder_clhca.h @@ -30,25 +30,25 @@ void clHCA_delete(clHCA *); int clHCA_DecodeHeader(clHCA *, const void *data, unsigned int size); typedef struct clHCA_stInfo { - unsigned int version; - unsigned int headerSize; - unsigned int samplingRate; - unsigned int channelCount; - unsigned int blockSize; - unsigned int blockCount; + unsigned int version; + unsigned int headerSize; + unsigned int samplingRate; + unsigned int channelCount; + unsigned int blockSize; + unsigned int blockCount; unsigned int encoderDelay; /* samples appended to the beginning */ unsigned int encoderPadding; /* samples appended to the end */ - unsigned int loopEnabled; - unsigned int loopStartBlock; - unsigned int loopEndBlock; + unsigned int loopEnabled; + unsigned int loopStartBlock; + unsigned int loopEndBlock; 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; - unsigned int encryptionEnabled; /* requires keycode */ + const char *comment; + unsigned int encryptionEnabled; /* requires keycode */ - /* Derived sample formulas: - * - sample count: blockCount*samplesPerBlock - encoderDelay - encoderPadding; + /* Derived sample formulas: + * - sample count: blockCount*samplesPerBlock - encoderDelay - encoderPadding; * - loop start sample = loopStartBlock*samplesPerBlock - encoderDelay + loopStartDelay * - loop end sample = loopEndBlock*samplesPerBlock - encoderDelay + (samplesPerBlock - info.loopEndPadding) */ diff --git a/Frameworks/vgmstream/vgmstream/src/coding/imuse_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/imuse_decoder.c index 9ce7c5460..3b9d35f9d 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/imuse_decoder.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/imuse_decoder.c @@ -289,8 +289,8 @@ imuse_codec_data* init_imuse(STREAMFILE* sf, int channels) { while (counter > 0) { if (counter & i) value += step; - step >>= 1; - counter >>= 1; + step >>= 1; + counter >>= 1; } data->adpcm_table[i + j * 64] = value; /* non sequential: all 64 [0]s, [1]s ... [88]s */ diff --git a/Frameworks/vgmstream/vgmstream/src/coding/mpeg_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/mpeg_decoder.c index f93da4bf4..d73ae220e 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/mpeg_decoder.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/mpeg_decoder.c @@ -250,11 +250,11 @@ static void decode_mpeg_standard(VGMSTREAMCHANNEL* stream, mpeg_codec_data* data data->bytes_in_buffer = read_streamfile(data->buffer,stream->offset,data->buffer_size,stream->streamfile); /* end of stream, fill rest with 0s */ - if (data->bytes_in_buffer <= 0) { - VGM_ASSERT(samples_to_do < samples_done, "MPEG: end of stream, filling %i\n", (samples_to_do - samples_done)); - memset(outbuf + samples_done * channels, 0, (samples_to_do - samples_done) * channels * sizeof(sample)); - break; - } + if (data->bytes_in_buffer <= 0) { + VGM_ASSERT(samples_to_do < samples_done, "MPEG: end of stream, filling %i\n", (samples_to_do - samples_done)); + memset(outbuf + samples_done * channels, 0, (samples_to_do - samples_done) * channels * sizeof(sample)); + break; + } data->buffer_full = 1; data->buffer_used = 0; diff --git a/Frameworks/vgmstream/vgmstream/src/coding/relic_decoder_lib.c b/Frameworks/vgmstream/vgmstream/src/coding/relic_decoder_lib.c index 7e0501469..52d85cbf4 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/relic_decoder_lib.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/relic_decoder_lib.c @@ -26,8 +26,8 @@ extern void fft(int n, float* xRe, float* xIm, float* yRe, float* yIm); #define RELIC_MAX_SIZE RELIC_SIZE_HIGH #define RELIC_MAX_FREQ (RELIC_MAX_SIZE / 2) #define RELIC_MAX_FFT (RELIC_MAX_SIZE / 4) -#define RELIC_MIN_BITRATE 256 -#define RELIC_MAX_BITRATE 2048 +#define RELIC_MIN_BITRATE 256 +#define RELIC_MAX_BITRATE 2048 //#define RELIC_MAX_FRAME_SIZE ((RELIC_MAX_BITRATE / 8) + 0x04) /* extra 0x04 for the bitreader */ diff --git a/Frameworks/vgmstream/vgmstream/src/coding/ws_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/ws_decoder.c index 3dc530a2f..ea0a36edd 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/ws_decoder.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/ws_decoder.c @@ -6,24 +6,22 @@ /* Based on Valery V. Anisimovsky's WS-AUD.txt */ -static char WSTable2bit[4]={-2,-1,0,1}; -static char WSTable4bit[16]={-9,-8,-6,-5,-4,-3,-2,-1, - 0, 1, 2, 3, 4, 5 ,6, 8}; +static char WSTable2bit[4] = { -2,-1,0,1 }; +static char WSTable4bit[16] = { -9,-8,-6,-5,-4,-3,-2,-1, 0, 1, 2, 3, 4, 5 ,6, 8 }; /* We pass in the VGMSTREAM here, unlike in other codings, because the decoder has to know about the block structure. */ void decode_ws(VGMSTREAM * vgmstream, int channel, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { - VGMSTREAMCHANNEL * stream = &(vgmstream->ch[channel]); - int16_t hist = stream->adpcm_history1_16; + int16_t hist = stream->adpcm_history1_16; off_t offset = stream->offset; int samples_left_in_frame = stream->samples_left_in_frame; off_t header_off = stream->frame_header_offset; - int i; - int32_t sample_count; - + int i; + int32_t sample_count; + if (vgmstream->ws_output_size == vgmstream->current_block_size) { /* uncompressed, we just need to convert to 16-bit */ for (i=first_sample,sample_count=0; icurrent_block_size, 1); break; case coding_XBOX_IMA: block_samples = xbox_ima_bytes_to_samples(vgmstream->current_block_size, 1); break; case coding_NGC_DSP: block_samples = dsp_bytes_to_samples(vgmstream->current_block_size, 1); break; - case coding_PSX: block_samples = ps_bytes_to_samples(vgmstream->current_block_size,1); break; + case coding_PSX: block_samples = ps_bytes_to_samples(vgmstream->current_block_size,1); break; default: VGM_LOG("BLOCKED: missing codec\n"); return; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/pc_adp.c b/Frameworks/vgmstream/vgmstream/src/meta/adp_bos.c similarity index 96% rename from Frameworks/vgmstream/vgmstream/src/meta/pc_adp.c rename to Frameworks/vgmstream/vgmstream/src/meta/adp_bos.c index de7a56349..38b05de20 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/pc_adp.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/adp_bos.c @@ -5,7 +5,7 @@ VGMSTREAM* init_vgmstream_adp_bos(STREAMFILE* sf) { VGMSTREAM* vgmstream = NULL; off_t start_offset; int loop_flag = 0; - int channels; + int channels; /* checks */ if (!check_extensions(sf,"adp")) @@ -19,7 +19,7 @@ VGMSTREAM* init_vgmstream_adp_bos(STREAMFILE* sf) { start_offset = 0x18; - /* build the VGMSTREAM */ + /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channels, loop_flag); if (!vgmstream) goto fail; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/adx.c b/Frameworks/vgmstream/vgmstream/src/meta/adx.c index 3d1271453..62937b736 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/adx.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/adx.c @@ -83,14 +83,14 @@ VGMSTREAM* init_vgmstream_adx_subkey(STREAMFILE* sf, uint16_t subkey) { coding_type = coding_CRI_ADX_enc_8; version = 0x0400; } - VGM_ASSERT(version != 0x0400, "ADX: keystring not found\n"); + vgm_asserti(version != 0x0400, "ADX: decryption keystring not found\n"); } else if (version == 0x0409) { if (find_adx_key(sf, 9, &xor_start, &xor_mult, &xor_add, subkey)) { coding_type = coding_CRI_ADX_enc_9; version = 0x0400; } - VGM_ASSERT(version != 0x0400, "ADX: keycode not found\n"); + vgm_asserti(version != 0x0400, "ADX: decryption keycode not found\n"); } /* version + extra data */ diff --git a/Frameworks/vgmstream/vgmstream/src/meta/awb.c b/Frameworks/vgmstream/vgmstream/src/meta/awb.c index e5843529c..834fe2742 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/awb.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/awb.c @@ -234,7 +234,7 @@ static void load_awb_name(STREAMFILE* sf, STREAMFILE* sf_acb, VGMSTREAM* vgmstre } } - /* probably loaded */ + /* probably loaded */ load_acb_wave_name(sf_acb, vgmstream, waveid, port, is_memory); close_streamfile(sf_acb); diff --git a/Frameworks/vgmstream/vgmstream/src/meta/bik.c b/Frameworks/vgmstream/vgmstream/src/meta/bik.c index 8b0bf0def..58643d9cb 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/bik.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/bik.c @@ -1,147 +1,154 @@ -#include "meta.h" -#include "../coding/coding.h" -#include "../util.h" - -static int bink_get_info(STREAMFILE *streamFile, int target_subsong, int * out_total_streams, size_t *out_stream_size, int * out_channel_count, int * out_sample_rate, int * out_num_samples); - -/* BINK 1/2 - RAD Game Tools movies (audio/video format) */ -VGMSTREAM * init_vgmstream_bik(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - int channel_count = 0, loop_flag = 0, sample_rate = 0, num_samples = 0; - int total_subsongs = 0, target_subsong = streamFile->stream_index; - size_t stream_size; - - /* checks */ - /* .bik/bik2/bk2: standard - * .bika = fake extension for demuxed audio */ - if (!check_extensions(streamFile,"bik,bika,bik2,bk2")) - goto fail; - - /* check header "BIK" (bink 1) or "KB2" (bink 2), followed by version-char (audio is the same for both) */ - if ((read_32bitBE(0x00,streamFile) & 0xffffff00) != 0x42494B00 && - (read_32bitBE(0x00,streamFile) & 0xffffff00) != 0x4B423200 ) goto fail; - - /* find target stream info and samples */ - if (!bink_get_info(streamFile, target_subsong, &total_subsongs, &stream_size, &channel_count, &sample_rate, &num_samples)) - goto fail; - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count, loop_flag); - if (!vgmstream) goto fail; - - vgmstream->layout_type = layout_none; - vgmstream->sample_rate = sample_rate; - vgmstream->num_samples = num_samples; - vgmstream->num_streams = total_subsongs; - vgmstream->stream_size = stream_size; - vgmstream->meta_type = meta_BINK; - -#ifdef VGM_USE_FFMPEG - { - /* target_subsong should be passed manually */ - - vgmstream->codec_data = init_ffmpeg_header_offset_subsong(streamFile, NULL,0, 0x0,get_streamfile_size(streamFile), target_subsong); - if (!vgmstream->codec_data) goto fail; - vgmstream->coding_type = coding_FFmpeg; - } -#else - goto fail; -#endif - - return vgmstream; - -fail: - close_vgmstream(vgmstream); - return NULL; -} - -/** - * Gets stream info, and number of samples in a BINK file by reading all frames' headers (as it's VBR), - * as they are not in the main header. The header for BINK1 and 2 is the same. - * (a ~3 min movie needs ~6000-7000 frames = fseeks, should be fast enough) - */ -static int bink_get_info(STREAMFILE *streamFile, int target_subsong, int * out_total_subsongs, size_t * out_stream_size, int * out_channel_count, int * out_sample_rate, int * out_num_samples) { - uint32_t *offsets = NULL; - uint32_t num_frames, num_samples_b = 0; - off_t cur_offset; - int i, j, sample_rate, channel_count; - int total_subsongs; - size_t stream_size = 0; - - size_t filesize = get_streamfile_size(streamFile); - uint32_t signature = (read_32bitBE(0x00,streamFile) & 0xffffff00); - uint8_t revision = (read_32bitBE(0x00,streamFile) & 0xFF); - - if (read_32bitLE(0x04,streamFile)+ 0x08 != filesize) - goto fail; - - num_frames = (uint32_t)read_32bitLE(0x08,streamFile); - if (num_frames == 0 || num_frames > 0x100000) goto fail; /* something must be off (avoids big allocs below) */ - - /* multichannel/multilanguage audio is usually N streams of stereo/mono, no way to know channel layout */ - total_subsongs = read_32bitLE(0x28,streamFile); - if (target_subsong == 0) target_subsong = 1; - if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1 || total_subsongs > 255) goto fail; - - /* find stream info and position in offset table */ - cur_offset = 0x2c; - if ((signature == 0x42494B00 && (revision == 0x6b)) || /* k */ - (signature == 0x4B423200 && (revision == 0x69 || revision == 0x6a || revision == 0x6b))) /* i,j,k */ - cur_offset += 0x04; /* unknown v2 header field */ - cur_offset += 0x04*total_subsongs; /* skip streams max packet bytes */ - sample_rate = (uint16_t)read_16bitLE(cur_offset+0x04*(target_subsong-1)+0x00,streamFile); - channel_count = (uint16_t)read_16bitLE(cur_offset+0x04*(target_subsong-1)+0x02,streamFile) & 0x2000 ? 2 : 1; /* stereo flag */ - cur_offset += 0x04*total_subsongs; /* skip streams info */ - cur_offset += 0x04*total_subsongs; /* skip streams ids */ - - - /* read frame offsets in a buffer, to avoid fseeking to the table back and forth */ - offsets = malloc(sizeof(uint32_t) * num_frames); - if (!offsets) goto fail; - - for (i=0; i < num_frames; i++) { - offsets[i] = read_32bitLE(cur_offset,streamFile) & 0xFFFFFFFE; /* mask first bit (= keyframe) */ - cur_offset += 0x4; - - if (offsets[i] > filesize) goto fail; - } - /* after the last index is the file size, validate just in case */ - if (read_32bitLE(cur_offset,streamFile) != filesize) goto fail; - - /* read each frame header and sum all samples - * a frame has N audio packets with a header (one per stream) + video packet */ - for (i=0; i < num_frames; i++) { - cur_offset = offsets[i]; - - /* read audio packet headers per stream */ - for (j=0; j < total_subsongs; j++) { - uint32_t ap_size = read_32bitLE(cur_offset+0x00,streamFile); /* not counting this int */ - - if (j == target_subsong-1) { - stream_size += 0x04 + ap_size; - if (ap_size > 0) - num_samples_b += read_32bitLE(cur_offset+0x04,streamFile); /* decoded samples in bytes */ - break; /* next frame */ - } - else { /* next stream packet or frame */ - cur_offset += 4 + ap_size; //todo sometimes ap_size doesn't include itself (+4), others it does? - } - } - } - - free(offsets); - - - if (out_total_subsongs) *out_total_subsongs = total_subsongs; - if (out_stream_size) *out_stream_size = stream_size; - if (out_sample_rate) *out_sample_rate = sample_rate; - if (out_channel_count) *out_channel_count = channel_count; - //todo returns a few more samples (~48) than binkconv.exe? - if (out_num_samples) *out_num_samples = num_samples_b / (2 * channel_count); - - return 1; - -fail: - free(offsets); - return 0; -} +#include "meta.h" +#include "../coding/coding.h" +#include "../util.h" + +static int bink_get_info(STREAMFILE* sf, int target_subsong, int* p_total_subsongs, size_t* p_stream_size, int* p_channels, int* p_sample_rate, int* p_num_samples); + +/* BINK 1/2 - RAD Game Tools movies (audio/video format) */ +VGMSTREAM* init_vgmstream_bik(STREAMFILE* sf) { + VGMSTREAM * vgmstream = NULL; + int channels = 0, loop_flag = 0, sample_rate = 0, num_samples = 0; + int total_subsongs = 0, target_subsong = sf->stream_index; + size_t stream_size; + + /* checks */ + /* .bik/bik2/bk2: standard + * .bika: fake extension for demuxed audio */ + if (!check_extensions(sf,"bik,bik2,bk2,bika")) + goto fail; + + /* check bink1/2 header, followed by version-char (audio is the same) */ + if ((read_32bitBE(0x00,sf) & 0xffffff00) != get_id32be("BIK\0") && + (read_32bitBE(0x00,sf) & 0xffffff00) != get_id32be("KB2\0")) + goto fail; + + /* find target stream info and samples */ + if (!bink_get_info(sf, target_subsong, &total_subsongs, &stream_size, &channels, &sample_rate, &num_samples)) + goto fail; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channels, loop_flag); + if (!vgmstream) goto fail; + + vgmstream->layout_type = layout_none; + vgmstream->sample_rate = sample_rate; + vgmstream->num_samples = num_samples; + vgmstream->num_streams = total_subsongs; + vgmstream->stream_size = stream_size; + vgmstream->meta_type = meta_BINK; + +#ifdef VGM_USE_FFMPEG + { + /* target_subsong should be passed manually */ + vgmstream->codec_data = init_ffmpeg_header_offset_subsong(sf, NULL,0, 0x0,0, target_subsong); + if (!vgmstream->codec_data) goto fail; + vgmstream->coding_type = coding_FFmpeg; + } +#else + goto fail; +#endif + + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} + +/** + * Gets stream info, and number of samples in a BINK file by reading all frames' headers (as it's VBR), + * as they are not in the main header. The header for BINK1 and 2 is the same. + * (a ~3 min movie needs ~6000-7000 frames = fseeks, should be fast enough) + */ +static int bink_get_info(STREAMFILE* sf, int target_subsong, int* p_total_subsongs, size_t* p_stream_size, int* p_channels, int* p_sample_rate, int* p_num_samples) { + uint32_t* offsets = NULL; + uint32_t num_frames, num_samples_b = 0; + off_t cur_offset; + int i, j, sample_rate, channels; + int total_subsongs; + size_t stream_size = 0; + + size_t filesize = get_streamfile_size(sf); + uint32_t signature = (read_32bitBE(0x00,sf) & 0xffffff00); + uint8_t revision = (read_32bitBE(0x00,sf) & 0xFF); + + + if (read_32bitLE(0x04,sf) + 0x08 != filesize) + goto fail; + + num_frames = (uint32_t)read_32bitLE(0x08,sf); + if (num_frames == 0 || num_frames > 0x100000) goto fail; /* something must be off (avoids big allocs below) */ + + /* multichannel/multilanguage audio is usually N streams of stereo/mono, no way to know channel layout */ + total_subsongs = read_32bitLE(0x28,sf); + if (total_subsongs < 1) { + vgm_logi("BIK: no audio in movie (ignore)\n"); + goto fail; + } + + if (target_subsong == 0) target_subsong = 1; + if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs > 255) goto fail; + + + /* find stream info and position in offset table */ + cur_offset = 0x2c; + if ((signature == 0x42494B00 && (revision == 0x6b)) || /* k */ + (signature == 0x4B423200 && (revision == 0x69 || revision == 0x6a || revision == 0x6b))) /* i,j,k */ + cur_offset += 0x04; /* unknown v2 header field */ + cur_offset += 0x04*total_subsongs; /* skip streams max packet bytes */ + sample_rate = (uint16_t)read_16bitLE(cur_offset+0x04*(target_subsong-1)+0x00,sf); + channels = (uint16_t)read_16bitLE(cur_offset+0x04*(target_subsong-1)+0x02,sf) & 0x2000 ? 2 : 1; /* stereo flag */ + cur_offset += 0x04*total_subsongs; /* skip streams info */ + cur_offset += 0x04*total_subsongs; /* skip streams ids */ + + + /* read frame offsets in a buffer, to avoid fseeking to the table back and forth */ + offsets = malloc(sizeof(uint32_t) * num_frames); + if (!offsets) goto fail; + + for (i=0; i < num_frames; i++) { + offsets[i] = read_32bitLE(cur_offset,sf) & 0xFFFFFFFE; /* mask first bit (= keyframe) */ + cur_offset += 0x4; + + if (offsets[i] > filesize) goto fail; + } + /* after the last index is the file size, validate just in case */ + if (read_32bitLE(cur_offset,sf) != filesize) goto fail; + + /* read each frame header and sum all samples + * a frame has N audio packets with a header (one per stream) + video packet */ + for (i=0; i < num_frames; i++) { + cur_offset = offsets[i]; + + /* read audio packet headers per stream */ + for (j=0; j < total_subsongs; j++) { + uint32_t ap_size = read_32bitLE(cur_offset+0x00,sf); /* not counting this int */ + + if (j == target_subsong-1) { + stream_size += 0x04 + ap_size; + if (ap_size > 0) + num_samples_b += read_32bitLE(cur_offset+0x04,sf); /* decoded samples in bytes */ + break; /* next frame */ + } + else { /* next stream packet or frame */ + cur_offset += 4 + ap_size; //todo sometimes ap_size doesn't include itself (+4), others it does? + } + } + } + + free(offsets); + + + if (p_total_subsongs) *p_total_subsongs = total_subsongs; + if (p_stream_size) *p_stream_size = stream_size; + if (p_sample_rate) *p_sample_rate = sample_rate; + if (p_channels) *p_channels = channels; + //todo returns a few more samples (~48) than binkconv.exe? + if (p_num_samples) *p_num_samples = num_samples_b / (2 * channels); + + return 1; + +fail: + free(offsets); + return 0; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/bkhd.c b/Frameworks/vgmstream/vgmstream/src/meta/bkhd.c index a31044b2d..459e91479 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/bkhd.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/bkhd.c @@ -1,5 +1,6 @@ #include "meta.h" #include "../coding/coding.h" +#include "../util/chunks.h" /* BKHD - Wwise soundbank container */ @@ -19,9 +20,9 @@ VGMSTREAM* init_vgmstream_bkhd(STREAMFILE* sf) { if (!check_extensions(sf,"bnk")) goto fail; - if (read_u32be(0x00, sf) == 0x414B424B) /* "AKBK" [Shadowrun (X360)] */ + if (is_id32be(0x00, sf, "AKBK")) /* [Shadowrun (X360)] */ base_offset = 0x0c; - if (read_u32be(base_offset + 0x00, sf) != 0x424B4844) /* "BKHD" */ + if (!is_id32be(base_offset + 0x00, sf, "BKHD")) goto fail; big_endian = guess_endianness32bit(base_offset + 0x04, sf); read_u32 = big_endian ? read_u32be : read_u32le; @@ -77,16 +78,41 @@ VGMSTREAM* init_vgmstream_bkhd(STREAMFILE* sf) { subfile_size = read_u32(offset + 0x14, sf); } else { - off_t didx_offset, data_offset, offset; - size_t didx_size; - if (!find_chunk(sf, 0x44494458, 0x00,0, &didx_offset, &didx_size, big_endian, 0)) /* "DIDX" */ - goto fail; - if (!find_chunk(sf, 0x44415441, 0x00,0, &data_offset, NULL, big_endian, 0)) /* "DATA" */ + enum { + CHUNK_DIDX = 0x44494458, /* "DIDX" */ + CHUNK_DATA = 0x44415441, /* "DATA" */ + }; + off_t didx_offset = 0, data_offset = 0, didx_size = 0, offset; + chunk_t rc = {0}; + + rc.be_size = big_endian; + rc.current = 0x00; + while (next_chunk(&rc, sf)) { + switch(rc.type) { + + case CHUNK_DIDX: + didx_offset = rc.offset; + didx_size = rc.size; + break; + + case CHUNK_DATA: + data_offset = rc.offset; + break; + + default: + break; + } + } + if (!didx_offset || !data_offset) goto fail; total_subsongs = didx_size / 0x0c; + if (total_subsongs < 1) { + vgm_logi("BKHD: bank has no subsongs (ignore)\n"); + goto fail; + } if (target_subsong == 0) target_subsong = 1; - if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail; + if (target_subsong > total_subsongs) goto fail; offset = didx_offset + (target_subsong - 1) * 0x0c; subfile_id = read_u32(offset + 0x00, sf); diff --git a/Frameworks/vgmstream/vgmstream/src/meta/bnsf.c b/Frameworks/vgmstream/vgmstream/src/meta/bnsf.c index 1805d1065..b4693065d 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/bnsf.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/bnsf.c @@ -166,7 +166,7 @@ static void find_bnsf_key(STREAMFILE* sf, off_t start, g7221_codec_data* data, u } VGM_ASSERT(best_score > 0, "BNSF: best key=%.24s (score=%i)\n", best_key, best_score); - VGM_ASSERT(best_score < 0, "BNSF: key not found\n"); + vgm_asserti(best_score < 0 , "BNSF: decryption key not found\n"); } #define BNSF_MIN_KEY_LEN 3 diff --git a/Frameworks/vgmstream/vgmstream/src/meta/btsnd.c b/Frameworks/vgmstream/vgmstream/src/meta/btsnd.c index b0afa30fd..8a670140f 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/btsnd.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/btsnd.c @@ -1,68 +1,53 @@ -/* -Wii U boot sound file for each game/app. -*/ - -#include "meta.h" -#include "../util.h" - -VGMSTREAM * init_vgmstream_btsnd(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - int channel_count = 2; - int loop_flag; - off_t start_offset = 0x8; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile, filename, sizeof(filename)); - if (strcasecmp("btsnd", filename_extension(filename))) - goto fail; - - /* Checking for loop start */ - if (read_32bitBE(0x4, streamFile) > 0) - loop_flag = 1; - else - loop_flag = 0; - - if (channel_count < 1) goto fail; - - /* build the VGMSTREAM */ - - vgmstream = allocate_vgmstream(channel_count, loop_flag); - if (!vgmstream) goto fail; - - /* fill in the vital statistics */ - vgmstream->sample_rate = 48000; - /* channels and loop flag are set by allocate_vgmstream */ - - // There's probably a better way to get the sample count... - vgmstream->num_samples = vgmstream->loop_end_sample = (get_streamfile_size(streamFile) - 8) / 4; - - vgmstream->loop_start_sample = read_32bitBE(0x4, streamFile); - - vgmstream->coding_type = coding_PCM16BE; - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = 0x2; // Constant for this format - vgmstream->meta_type = meta_WIIU_BTSND; - - /* open the file for reading by each channel */ - { - int i; - for (i = 0; ich[i].streamfile = streamFile->open(streamFile, filename, - STREAMFILE_DEFAULT_BUFFER_SIZE); - - if (!vgmstream->ch[i].streamfile) goto fail; - - vgmstream->ch[i].channel_start_offset = - vgmstream->ch[i].offset = - start_offset + i*vgmstream->interleave_block_size; - } - } - - return vgmstream; - - /* clean up anything we may have opened */ -fail: - if (vgmstream) close_vgmstream(vgmstream); - return NULL; -} +#include "meta.h" +#include "../coding/coding.h" + +/* .btsnd - Wii U boot sound file for each game/app */ +VGMSTREAM* init_vgmstream_btsnd(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; + int channels, loop_flag; + off_t start_offset, data_size; + int32_t num_samples, loop_start; + + + /* checks */ + if (!check_extensions(sf, "btsnd")) + goto fail; + + if (read_u32be(0x00,sf) != 0x02) + goto fail; + + loop_start = read_s32be(0x04, sf); + start_offset = 0x08; + + channels = 2; + loop_flag = loop_start > 0; + + /* extra check since format is so simple */ + data_size = get_streamfile_size(sf); + num_samples = pcm16_bytes_to_samples(data_size - start_offset, channels); + if (loop_start >= num_samples) + goto fail; + + + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channels, loop_flag); + if (!vgmstream) goto fail; + + vgmstream->meta_type = meta_WIIU_BTSND; + vgmstream->sample_rate = 48000; + vgmstream->num_samples = num_samples; + vgmstream->loop_start_sample = loop_start; + vgmstream->loop_end_sample = vgmstream->num_samples; + + vgmstream->coding_type = coding_PCM16BE; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x02; + + if (!vgmstream_open_stream(vgmstream, sf, start_offset)) + goto fail; + return vgmstream; +fail: + close_vgmstream(vgmstream); + return NULL; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/cri_utf.c b/Frameworks/vgmstream/vgmstream/src/meta/cri_utf.c index 94851fed8..e21929164 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/cri_utf.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/cri_utf.c @@ -1,13 +1,14 @@ #include "cri_utf.h" +#include "../util/log.h" #define COLUMN_BITMASK_FLAG 0xf0 #define COLUMN_BITMASK_TYPE 0x0f enum columna_flag_t { - COLUMN_FLAG_NAME = 0x10, - COLUMN_FLAG_DEFAULT = 0x20, - COLUMN_FLAG_ROW = 0x40, - COLUMN_FLAG_UNDEFINED = 0x80 /* shouldn't exist */ + COLUMN_FLAG_NAME = 0x10, + COLUMN_FLAG_DEFAULT = 0x20, + COLUMN_FLAG_ROW = 0x40, + COLUMN_FLAG_UNDEFINED = 0x80 /* shouldn't exist */ }; enum column_type_t { @@ -113,7 +114,7 @@ utf_context* utf_open(STREAMFILE* sf, uint32_t table_offset, int* p_rows, const /* 00: early (32b rows_offset?), 01: +2017 (no apparent differences) */ if (utf->version != 0x00 && utf->version != 0x01) { - VGM_LOG("@UTF: unknown version\n"); + vgm_logi("@UTF: unknown version\n"); } if (utf->table_offset + utf->table_size > get_streamfile_size(sf)) goto fail; @@ -169,7 +170,7 @@ utf_context* utf_open(STREAMFILE* sf, uint32_t table_offset, int* p_rows, const !(utf->schema[i].flag & COLUMN_FLAG_NAME) || ((utf->schema[i].flag & COLUMN_FLAG_DEFAULT) && (utf->schema[i].flag & COLUMN_FLAG_ROW)) || (utf->schema[i].flag & COLUMN_FLAG_UNDEFINED) ) { - VGM_LOG("@UTF: unknown column flag combo found\n"); + vgm_logi("@UTF: unknown column flag combo found\n"); goto fail; } @@ -197,7 +198,7 @@ utf_context* utf_open(STREAMFILE* sf, uint32_t table_offset, int* p_rows, const //case COLUMN_TYPE_UINT128: // value_size = 0x16; default: - VGM_LOG("@UTF: unknown column type\n"); + vgm_logi("@UTF: unknown column type\n"); goto fail; } @@ -228,7 +229,7 @@ utf_context* utf_open(STREAMFILE* sf, uint32_t table_offset, int* p_rows, const return utf; fail: utf_close(utf); - VGM_LOG("@UTF: fail\n"); + vgm_logi("@UTF: init failure\n"); return NULL; } diff --git a/Frameworks/vgmstream/vgmstream/src/meta/deblock_streamfile.c b/Frameworks/vgmstream/vgmstream/src/meta/deblock_streamfile.c index 681b4d35d..bd1b53051 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/deblock_streamfile.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/deblock_streamfile.c @@ -1,4 +1,5 @@ #include "deblock_streamfile.h" +#include "../util/log.h" //todo move to utils or something diff --git a/Frameworks/vgmstream/vgmstream/src/meta/dmsg_segh.c b/Frameworks/vgmstream/vgmstream/src/meta/dmsg_segh.c index 900d7188b..91142a9e3 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/dmsg_segh.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/dmsg_segh.c @@ -1,48 +1,6 @@ #include "meta.h" #include "../coding/coding.h" - -typedef struct { - uint32_t type; - uint32_t size; - uint32_t offset; - off_t current; - off_t max; - int le_type; - int be_size; - int full_size; -} chunk_t; - -static int next_chunk(chunk_t* chunk, STREAMFILE* sf) { - uint32_t (*read_u32type)(off_t,STREAMFILE*) = !chunk->le_type ? read_u32be : read_u32le; - uint32_t (*read_u32size)(off_t,STREAMFILE*) = chunk->be_size ? read_u32be : read_u32le; - - if (chunk->max == 0) - chunk->max = get_streamfile_size(sf); - - if (chunk->current >= chunk->max) - return 0; - /* can be used to signal "stop" */ - if (chunk->current < 0) - return 0; - - chunk->type = read_u32type(chunk->current + 0x00,sf); - chunk->size = read_u32size(chunk->current + 0x04,sf); - - chunk->offset = chunk->current + 0x04 + 0x04; - chunk->current += chunk->full_size ? chunk->size : 0x08 + chunk->size; - //;VGM_LOG("CHUNK: %x, %x, %x\n", dc.offset, chunk->type, chunk->size); - - /* read past data */ - if (chunk->type == 0xFFFFFFFF || chunk->size == 0xFFFFFFFF) - return 0; - - /* empty chunk with 0 size, seen in some formats (XVAG uses it as end marker, Wwise doesn't) */ - if (chunk->type == 0 || chunk->size == 0) - return 0; - - /* more chunks remain */ - return 1; -} +#include "../util/chunks.h" enum { CHUNK_RIFF = 0x52494646, /* "RIFF" */ diff --git a/Frameworks/vgmstream/vgmstream/src/meta/dsp_adx.c b/Frameworks/vgmstream/vgmstream/src/meta/dsp_adx.c index addf8dd74..42cbb3d8e 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/dsp_adx.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/dsp_adx.c @@ -2,49 +2,47 @@ #include "../coding/coding.h" #include "../util.h" -/* .ADX - from Xenoblade 3D */ -/* Xenoblade Chronicles 3D uses an adx extension as with - * the Wii version, but it's actually DSP ADPCM. */ -VGMSTREAM * init_vgmstream_dsp_adx(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - int loop_flag, channel_count; +/* .ADX - from Xenoblade 3D (3DS) */ +VGMSTREAM* init_vgmstream_dsp_adx(STREAMFILE *sf) { + VGMSTREAM* vgmstream = NULL; + int loop_flag, channels; int channel_header_spacing = 0x34; - - /* check extension, case insensitive */ - if (!check_extensions(streamFile,"adx")) goto fail; - /* check header */ - if (read_32bitBE(0,streamFile)!=0x02000000) goto fail; + /* checks */ + if (!check_extensions(sf,"adx")) + goto fail; - channel_count = read_32bitLE(0, streamFile); - loop_flag = read_16bitLE(0x6e, streamFile); + if (read_u32be(0x00,sf) != 0x02000000) + goto fail; - if (channel_count > 2 || channel_count < 0) goto fail; + channels = read_32bitLE(0, sf); + loop_flag = read_16bitLE(0x6e, sf); - vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (channels > 2 || channels < 0) goto fail; + + vgmstream = allocate_vgmstream(channels, loop_flag); if (!vgmstream) goto fail; vgmstream->coding_type = coding_NGC_DSP; vgmstream->layout_type = layout_none; vgmstream->meta_type = meta_XB3D_ADX; - vgmstream->sample_rate = read_32bitLE(0x70,streamFile); - vgmstream->num_samples = read_32bitLE(0x74, streamFile); - vgmstream->loop_start_sample = read_32bitLE(0x78, streamFile); - vgmstream->loop_end_sample = read_32bitLE(0x7c, streamFile); - - dsp_read_coefs_le(vgmstream,streamFile, 0x4, channel_header_spacing); + vgmstream->sample_rate = read_32bitLE(0x70,sf); + vgmstream->num_samples = read_32bitLE(0x74, sf); + vgmstream->loop_start_sample = read_32bitLE(0x78, sf); + vgmstream->loop_end_sample = read_32bitLE(0x7c, sf); + dsp_read_coefs_le(vgmstream,sf, 0x4, channel_header_spacing); /* semi-interleave: manually open streams at offset */ { char filename[PATH_LIMIT]; int i; - streamFile->get_name(streamFile,filename,sizeof(filename)); - for (i = 0; ich[i].streamfile = streamFile->open(streamFile, filename, STREAMFILE_DEFAULT_BUFFER_SIZE); + sf->get_name(sf,filename,sizeof(filename)); + for (i = 0; ich[i].streamfile = sf->open(sf, filename, STREAMFILE_DEFAULT_BUFFER_SIZE); vgmstream->ch[i].channel_start_offset = - vgmstream->ch[i].offset = read_32bitLE(0x34+i*channel_header_spacing, streamFile); + vgmstream->ch[i].offset = read_32bitLE(0x34+i*channel_header_spacing, sf); if (!vgmstream->ch[i].streamfile) goto fail; } } diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ea_schl.c b/Frameworks/vgmstream/vgmstream/src/meta/ea_schl.c index 2bab4a253..64b3ea7b0 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ea_schl.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ea_schl.c @@ -193,13 +193,14 @@ VGMSTREAM* init_vgmstream_ea_schl_video(STREAMFILE* sf) { /* check extension */ /* .uv: early */ /* .dct: early-mid [ex. Need for Speed II SE (PC), FIFA 98 (PC)] */ + /* .wve: early-mid [Madden NFL 99 (PC)] */ /* .mad: mid */ /* .vp6: late */ if (check_extensions(sf, "uv,dct")) { /* starts with audio header block */ if (read_32bitBE(0x00, sf) != EA_BLOCKID_HEADER) /* "SCHl" */ goto fail; - } else if (check_extensions(sf, "mad")) { + } else if (check_extensions(sf, "mad,wve")) { /* check initial movie block id */ if (read_32bitBE(0x00, sf) != 0x4D41446B) /* "MADk" */ goto fail; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/fsb5.c b/Frameworks/vgmstream/vgmstream/src/meta/fsb5.c index 430572a13..024fe6c18 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/fsb5.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/fsb5.c @@ -18,28 +18,29 @@ typedef struct { int32_t loop_end; int loop_flag; - off_t sample_header_offset; size_t sample_header_size; size_t name_table_size; size_t sample_data_size; size_t base_header_size; - off_t extradata_offset; - size_t extradata_size; + uint32_t extradata_offset; + uint32_t extradata_size; - off_t stream_offset; - size_t stream_size; - off_t name_offset; + uint32_t stream_offset; + uint32_t stream_size; + uint32_t name_offset; } fsb5_header; /* ********************************************************************************** */ -static layered_layout_data* build_layered_fsb5(STREAMFILE* sf, fsb5_header* fsb5); +static layered_layout_data* build_layered_fsb5(STREAMFILE* sf, STREAMFILE* sb, fsb5_header* fsb5); /* FSB5 - Firelight's FMOD Studio SoundBank format */ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) { VGMSTREAM* vgmstream = NULL; + STREAMFILE* sb = NULL; fsb5_header fsb5 = {0}; + uint32_t offset; int target_subsong = sf->stream_index; int i; @@ -53,7 +54,7 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) { if (!is_id32be(0x00,sf, "FSB5")) goto fail; - /* 0x00 is rare (seen in Tales from Space Vita) */ + /* v0 is rare (seen in Tales from Space Vita) */ fsb5.version = read_u32le(0x04,sf); if (fsb5.version != 0x00 && fsb5.version != 0x01) goto fail; @@ -63,44 +64,48 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) { fsb5.name_table_size = read_u32le(0x10,sf); fsb5.sample_data_size = read_u32le(0x14,sf); fsb5.codec = read_u32le(0x18,sf); - /* version 0x01 - 0x1c(4): zero, 0x24(16): hash, 0x34(8): unk - * version 0x00 has an extra field (always 0?) at 0x1c */ + /* 0x1c: zero */ if (fsb5.version == 0x01) { - /* found by tests and assumed to be flags, no games known */ - fsb5.flags = read_u32le(0x20,sf); + fsb5.flags = read_u32le(0x20,sf); /* found by tests and assumed to be flags, no games known */ + /* 0x24: 128-bit hash */ + /* 0x34: unknown (64-bit sub-hash?) */ + fsb5.base_header_size = 0x3c; + } + else { + /* 0x20: zero/flags? */ + /* 0x24: zero/flags? */ + /* 0x28: 128-bit hash */ + /* 0x38: unknown (64-bit sub-hash?) */ + fsb5.base_header_size = 0x40; } - fsb5.base_header_size = (fsb5.version==0x00) ? 0x40 : 0x3C; if ((fsb5.sample_header_size + fsb5.name_table_size + fsb5.sample_data_size + fsb5.base_header_size) != get_streamfile_size(sf)) { - VGM_LOG("FSB5: bad size (%x + %x + %x + %x != %x)\n", fsb5.sample_header_size, fsb5.name_table_size, fsb5.sample_data_size, fsb5.base_header_size, get_streamfile_size(sf)); + vgm_logi("FSB5: wrong size, expected %x + %x + %x + %x vs %x (re-rip)\n", fsb5.sample_header_size, fsb5.name_table_size, fsb5.sample_data_size, fsb5.base_header_size, get_streamfile_size(sf)); goto fail; } if (target_subsong == 0) target_subsong = 1; if (target_subsong > fsb5.total_subsongs || fsb5.total_subsongs <= 0) goto fail; - fsb5.sample_header_offset = fsb5.base_header_size; - /* find target stream header and data offset, and read all needed values for later use * (reads one by one as the size of a single stream header is variable) */ + offset = fsb5.base_header_size; for (i = 0; i < fsb5.total_subsongs; i++) { - size_t stream_header_size = 0; - off_t data_offset = 0; - uint32_t sample_mode1, sample_mode2; /* maybe one uint64? */ + uint32_t stream_header_size = 0; + uint32_t data_offset = 0; + uint64_t sample_mode; - sample_mode1 = read_u32le(fsb5.sample_header_offset+0x00,sf); - sample_mode2 = read_u32le(fsb5.sample_header_offset+0x04,sf); + sample_mode = read_u64le(offset+0x00,sf); stream_header_size += 0x08; /* get samples */ - fsb5.num_samples = ((sample_mode2 >> 2) & 0x3FFFFFFF); /* bits2: 31..2 (30) */ + fsb5.num_samples = ((sample_mode >> 34) & 0x3FFFFFFF); /* bits: 63..34 (30) */ - /* get offset inside data section */ - /* up to 0x07FFFFFF * 0x20 = full 32b offset 0xFFFFFFE0 */ - data_offset = (((sample_mode2 & 0x03) << 25) | ((sample_mode1 >> 7) & 0x1FFFFFF)) << 5; /* bits2: 1..0 (2) | bits1: 31..8 (25) */ + /* get offset inside data section (max 32b offset 0xFFFFFFE0) */ + data_offset = ((sample_mode >> 7) & 0x07FFFFFF) << 5; /* bits: 33..8 (25) */ /* get channels */ - switch ((sample_mode1 >> 5) & 0x03) { /* bits1: 7..6 (2) */ + switch ((sample_mode >> 5) & 0x03) { /* bits: 7..6 (2) */ case 0: fsb5.channels = 1; break; case 1: fsb5.channels = 2; break; case 2: fsb5.channels = 6; break; /* some Dark Souls 2 MPEG; some IMA ADPCM */ @@ -111,7 +116,7 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) { } /* get sample rate */ - switch ((sample_mode1 >> 1) & 0x0f) { /* bits1: 5..1 (4) */ + switch ((sample_mode >> 1) & 0x0f) { /* bits: 5..1 (4) */ case 0: fsb5.sample_rate = 4000; break; case 1: fsb5.sample_rate = 8000; break; case 2: fsb5.sample_rate = 11000; break; @@ -129,8 +134,8 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) { } /* get extra flags */ - if (sample_mode1 & 0x01) { /* bits1: 0 (1) */ - off_t extraflag_offset = fsb5.sample_header_offset+0x08; + if (sample_mode & 0x01) { /* bits: 0 (1) */ + uint32_t extraflag_offset = offset + 0x08; uint32_t extraflag, extraflag_type, extraflag_size, extraflag_end; do { @@ -217,7 +222,7 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) { fsb5.channels = fsb5.channels * fsb5.layers; break; default: - VGM_LOG("FSB5: stream %i unknown flag 0x%x at %x + 0x04 (size 0x%x)\n", i, extraflag_type, (uint32_t)extraflag_offset, extraflag_size); + vgm_logi("FSB5: stream %i unknown flag 0x%x at %x + 0x04 + 0x%x (report)\n", i, extraflag_type, extraflag_offset, extraflag_size); break; } } @@ -242,11 +247,10 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) { fsb5.stream_size = fsb5.sample_data_size - data_offset; } else { - off_t next_data_offset; - uint32_t next_sample_mode1, next_sample_mode2; - next_sample_mode1 = read_u32le(fsb5.sample_header_offset+stream_header_size+0x00,sf); - next_sample_mode2 = read_u32le(fsb5.sample_header_offset+stream_header_size+0x04,sf); - next_data_offset = (((next_sample_mode2 & 0x03) << 25) | ((next_sample_mode1 >> 7) & 0x1FFFFFF)) << 5; + uint32_t next_data_offset; + uint64_t next_sample_mode; + next_sample_mode = read_u64le(offset+stream_header_size+0x00,sf); + next_data_offset = ((next_sample_mode >> 7) & 0x07FFFFFF) << 5; fsb5.stream_size = next_data_offset - data_offset; } @@ -255,9 +259,9 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) { } /* continue searching target */ - fsb5.sample_header_offset += stream_header_size; + offset += stream_header_size; } - /* target stream not found*/ + if (!fsb5.stream_offset || !fsb5.stream_size) goto fail; @@ -268,6 +272,17 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) { } + /* FSB5 can hit +2GB offsets, but since decoders aren't ready to handle that use a subfile to hide big offsets + * (some FSB5 CLI versions make buggy offsets = bad output but this was fixed later) */ + if (fsb5.stream_offset > 0x7FFFFFFF) { + sb = setup_subfile_streamfile(sf, fsb5.stream_offset, fsb5.stream_size, NULL); + fsb5.stream_offset = 0x00; + } + else { + sb = sf; + } + + /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(fsb5.channels, fsb5.loop_flag); if (!vgmstream) goto fail; @@ -282,7 +297,7 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) { vgmstream->stream_size = fsb5.stream_size; vgmstream->meta_type = meta_FSB5; if (fsb5.name_offset) - read_string(vgmstream->stream_name,STREAM_NAME_SIZE, fsb5.name_offset,sf); + read_string(vgmstream->stream_name,STREAM_NAME_SIZE, fsb5.name_offset, sf); switch (fsb5.codec) { case 0x00: /* FMOD_SOUND_FORMAT_NONE */ @@ -301,11 +316,11 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) { break; case 0x03: /* FMOD_SOUND_FORMAT_PCM24 */ - VGM_LOG("FSB5: FMOD_SOUND_FORMAT_PCM24 found\n"); + vgm_logi("FSB5: FMOD_SOUND_FORMAT_PCM24 found (report)\n"); goto fail; case 0x04: /* FMOD_SOUND_FORMAT_PCM32 */ - VGM_LOG("FSB5: FMOD_SOUND_FORMAT_PCM32 found\n"); + vgm_logi("FSB5: FMOD_SOUND_FORMAT_PCM32 found (report)\n"); goto fail; case 0x05: /* FMOD_SOUND_FORMAT_PCMFLOAT [Anima: Gate of Memories (PC)] */ @@ -325,7 +340,7 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) { vgmstream->layout_type = layout_none; vgmstream->interleave_block_size = 0x02; } - dsp_read_coefs_be(vgmstream,sf,fsb5.extradata_offset,0x2E); + dsp_read_coefs_be(vgmstream, sf, fsb5.extradata_offset, 0x2E); break; case 0x07: /* FMOD_SOUND_FORMAT_IMAADPCM [Skylanders] */ @@ -359,12 +374,12 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) { block_count = fsb5.stream_size / block_size + (fsb5.stream_size % block_size ? 1 : 0); bytes = ffmpeg_make_riff_xma2(buf, 0x100, vgmstream->num_samples, fsb5.stream_size, vgmstream->channels, vgmstream->sample_rate, block_count, block_size); - vgmstream->codec_data = init_ffmpeg_header_offset(sf, buf,bytes, fsb5.stream_offset,fsb5.stream_size); + vgmstream->codec_data = init_ffmpeg_header_offset(sb, buf,bytes, fsb5.stream_offset, fsb5.stream_size); if (!vgmstream->codec_data) goto fail; vgmstream->coding_type = coding_FFmpeg; vgmstream->layout_type = layout_none; - xma_fix_raw_samples(vgmstream, sf, fsb5.stream_offset,fsb5.stream_size, 0, 0,0); /* samples look ok */ + xma_fix_raw_samples(vgmstream, sb, fsb5.stream_offset, fsb5.stream_size, 0, 0,0); /* samples look ok */ break; } #endif @@ -375,7 +390,7 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) { cfg.fsb_padding = (vgmstream->channels > 2 ? 16 : 4); /* observed default */ - vgmstream->codec_data = init_mpeg_custom(sf, fsb5.stream_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_FSB, &cfg); + vgmstream->codec_data = init_mpeg_custom(sb, fsb5.stream_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_FSB, &cfg); if (!vgmstream->codec_data) goto fail; vgmstream->layout_type = layout_none; break; @@ -387,7 +402,7 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) { fsb5.layers = (fsb5.channels <= 2) ? 1 : (fsb5.channels+1) / 2; if (fsb5.layers > 1) { - vgmstream->layout_data = build_layered_fsb5(sf, &fsb5); + vgmstream->layout_data = build_layered_fsb5(sf, sb, &fsb5); if (!vgmstream->layout_data) goto fail; vgmstream->coding_type = coding_CELT_FSB; vgmstream->layout_type = layout_layered; @@ -415,7 +430,7 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) { if (fsb5.layers > 1) { /* multichannel made of various layers [Little Big Planet (Vita)] */ - vgmstream->layout_data = build_layered_fsb5(sf, &fsb5); + vgmstream->layout_data = build_layered_fsb5(sf, sb, &fsb5); if (!vgmstream->layout_data) goto fail; vgmstream->coding_type = coding_ATRAC9; vgmstream->layout_type = layout_layered; @@ -449,7 +464,7 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) { /* XWMA encoder only does up to 6ch (doesn't use FSB multistreams for more) */ bytes = ffmpeg_make_riff_xwma(buf,0x100, format, fsb5.stream_size, vgmstream->channels, vgmstream->sample_rate, average_bps, block_align); - vgmstream->codec_data = init_ffmpeg_header_offset(sf, buf,bytes, fsb5.stream_offset,fsb5.stream_size); + vgmstream->codec_data = init_ffmpeg_header_offset(sb, buf,bytes, fsb5.stream_offset, fsb5.stream_size); if ( !vgmstream->codec_data ) goto fail; vgmstream->coding_type = coding_FFmpeg; vgmstream->layout_type = layout_none; @@ -465,7 +480,7 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) { cfg.sample_rate = fsb5.sample_rate; cfg.setup_id = read_u32le(fsb5.extradata_offset,sf); - vgmstream->codec_data = init_vorbis_custom(sf, fsb5.stream_offset, VORBIS_FSB, &cfg); + vgmstream->codec_data = init_vorbis_custom(sb, fsb5.stream_offset, VORBIS_FSB, &cfg); if (!vgmstream->codec_data) goto fail; vgmstream->coding_type = coding_VORBIS_custom; vgmstream->layout_type = layout_none; @@ -479,13 +494,13 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) { vgmstream->interleave_block_size = 0x8c; break; -#if 0 //disabled until some game is found, can be created in the GUI tool +#if 0 //disabled until some game is found, can be created in the GUI tool #ifdef VGM_USE_FFMPEG case 0x11: { /* FMOD_SOUND_FORMAT_OPUS */ - int skip = 312; //fsb_opus_get_encoder_delay(fsb5.stream_offset, sf); /* returns 120 but this seems correct */ + int skip = 312; //fsb_opus_get_encoder_delay(fsb5.stream_offset, sb); /* returns 120 but this seems correct */ //vgmstream->num_samples -= skip; - vgmstream->codec_data = init_ffmpeg_fsb_opus(sf, fsb5.stream_offset, fsb5.stream_size, vgmstream->channels, skip, vgmstream->sample_rate); + vgmstream->codec_data = init_ffmpeg_fsb_opus(sb, fsb5.stream_offset, fsb5.stream_size, vgmstream->channels, skip, vgmstream->sample_rate); if (!vgmstream->codec_data) goto fail; vgmstream->coding_type = coding_FFmpeg; vgmstream->layout_type = layout_none; @@ -494,22 +509,24 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) { #endif #endif default: - VGM_LOG("FSB5: unknown codec %x found\n", fsb5.codec); + vgm_logi("FSB5: unknown codec 0x%x (report)\n", fsb5.codec); goto fail; } - if (!vgmstream_open_stream(vgmstream,sf,fsb5.stream_offset)) + if (!vgmstream_open_stream(vgmstream, sb, fsb5.stream_offset)) goto fail; + if (sb != sf) close_streamfile(sb); return vgmstream; fail: + if (sb != sf) close_streamfile(sb); close_vgmstream(vgmstream); return NULL; } -static layered_layout_data* build_layered_fsb5(STREAMFILE* sf, fsb5_header* fsb5) { +static layered_layout_data* build_layered_fsb5(STREAMFILE* sf, STREAMFILE* sb, fsb5_header* fsb5) { layered_layout_data* data = NULL; STREAMFILE* temp_sf = NULL; size_t interleave, config = 0; @@ -526,9 +543,9 @@ static layered_layout_data* build_layered_fsb5(STREAMFILE* sf, fsb5_header* fsb5 /* 2ch+2ch..+1ch or 2ch+2ch..+2ch = check last layer */ layer_channels = (i+1 == fsb5->layers && fsb5->channels % 2 == 1) ? 1 : 2; - if (read_u32be(fsb5->stream_offset+0x00,sf) != 0x17C30DF3) /* FSB CELT frame ID */ + if (read_u32be(fsb5->stream_offset+0x00,sb) != 0x17C30DF3) /* FSB CELT frame ID */ goto fail; - interleave = 0x04+0x04+read_u32le(fsb5->stream_offset+0x04,sf); /* frame size */ + interleave = 0x04+0x04+read_u32le(fsb5->stream_offset+0x04,sb); /* frame size */ //todo unknown interleave for max quality odd channel streams (found in test files) /* FSB5 odd channels use 2ch+2ch...+1ch streams, and the last only goes up to 0x17a, and other @@ -609,7 +626,7 @@ static layered_layout_data* build_layered_fsb5(STREAMFILE* sf, fsb5_header* fsb5 } - temp_sf = setup_fsb5_streamfile(sf, fsb5->stream_offset, fsb5->stream_size, fsb5->layers, i, interleave); + temp_sf = setup_fsb5_streamfile(sb, fsb5->stream_offset, fsb5->stream_size, fsb5->layers, i, interleave); if (!temp_sf) goto fail; if (!vgmstream_open_stream(data->layers[i], temp_sf, 0x00)) diff --git a/Frameworks/vgmstream/vgmstream/src/meta/fsb5_fev.c b/Frameworks/vgmstream/vgmstream/src/meta/fsb5_fev.c index 4014716c9..80432a8f8 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/fsb5_fev.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/fsb5_fev.c @@ -128,7 +128,7 @@ VGMSTREAM* init_vgmstream_fsb5_fev_bank(STREAMFILE* sf) { } } - //;VGM_LOG("FSB5 FEV: offset=%lx, size=%x\n", subfile_offset,subfile_size); + //;VGM_LOG("FSB5 FEV: offset=%lx, size=%x\n", subfile_offset,subfile_size); temp_sf = setup_subfile_streamfile(sf, subfile_offset,subfile_size, "fsb"); if (!temp_sf) goto fail; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/hca.c b/Frameworks/vgmstream/vgmstream/src/meta/hca.c index f199872d0..d7694ca9d 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/hca.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/hca.c @@ -30,7 +30,10 @@ VGMSTREAM* init_vgmstream_hca_subkey(STREAMFILE* sf, uint16_t subkey) { /* init vgmstream and library's context, will validate the HCA */ hca_data = init_hca(sf); - if (!hca_data) goto fail; + if (!hca_data) { + vgm_logi("HCA: unknown format (report)\n"); + goto fail; + } hca_info = hca_get_info(hca_data); @@ -184,7 +187,7 @@ static void find_hca_key(hca_codec_data* hca_data, uint64_t* p_keycode, uint16_t done: VGM_ASSERT(best_score > 1, "HCA: best key=%08x%08x (score=%i)\n", (uint32_t)((*p_keycode >> 32) & 0xFFFFFFFF), (uint32_t)(*p_keycode & 0xFFFFFFFF), best_score); - VGM_ASSERT(best_score < 0, "HCA: key not found\n"); + vgm_asserti(best_score < 0, "HCA: decryption key not found\n"); } #ifdef HCA_BRUTEFORCE diff --git a/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h b/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h index c072bb12a..5c6d2695c 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h +++ b/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h @@ -722,6 +722,9 @@ static const hcakey_info hcakey_list[] = { // m HOLD'EM (Android) {369211553984367}, // 00014FCBC385AF6F + + // Sonic Colors Ultimate (multi) + {1991062320101111}, // 000712DC5250B6F7 }; #endif/*_HCA_KEYS_H_*/ diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ktsr.c b/Frameworks/vgmstream/vgmstream/src/meta/ktsr.c index 42aab2222..c74d69723 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ktsr.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ktsr.c @@ -23,8 +23,8 @@ typedef struct { uint32_t channel_layout; int is_external; - off_t stream_offsets[MAX_CHANNELS]; - size_t stream_sizes[MAX_CHANNELS]; + uint32_t stream_offsets[MAX_CHANNELS]; + uint32_t stream_sizes[MAX_CHANNELS]; off_t sound_name_offset; off_t config_name_offset; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/musc.c b/Frameworks/vgmstream/vgmstream/src/meta/musc.c index 0e80203bb..3ffa55378 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/musc.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/musc.c @@ -1,50 +1,50 @@ -#include "meta.h" -#include "../util.h" -#include "../coding/coding.h" -#include "../layout/layout.h" - -/* MUSC - from Krome's PS2 games (The Legend of Spyro, Ty the Tasmanian Tiger) */ -VGMSTREAM * init_vgmstream_musc(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - int loop_flag, channel_count; - off_t start_offset; - size_t data_size; - - /* .mus is the real extension, .musc is the header ID */ - if (!check_extensions(streamFile,"mus,musc")) - goto fail; - if (read_32bitBE(0x00,streamFile) != 0x4D555343) /* "MUSC" */ - goto fail; - - start_offset = read_32bitLE(0x10,streamFile); - data_size = read_32bitLE(0x14,streamFile); - if (start_offset + data_size != get_streamfile_size(streamFile)) - goto fail; - /* always does full loops unless it ends in silence */ - loop_flag = read_32bitBE(get_streamfile_size(streamFile) - 0x10,streamFile) != 0x0C000000; - channel_count = 2; - - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; - - vgmstream->sample_rate = (uint16_t)read_16bitLE(0x06,streamFile); - vgmstream->num_samples = ps_bytes_to_samples(data_size, channel_count); - vgmstream->loop_start_sample = 0; - vgmstream->loop_end_sample = vgmstream->num_samples; - - vgmstream->meta_type = meta_MUSC; - vgmstream->coding_type = coding_PSX; - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = read_32bitLE(0x18,streamFile) / 2; - - if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) - goto fail; - - return vgmstream; - -fail: - close_vgmstream(vgmstream); - return NULL; -} +#include "meta.h" +#include "../coding/coding.h" +#include "../layout/layout.h" + +/* MUSC - from Krome's PS2 games (The Legend of Spyro, Ty the Tasmanian Tiger) */ +VGMSTREAM* init_vgmstream_musc(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; + int loop_flag, channels; + off_t start_offset; + size_t data_size; + + + /* checks */ + /* .mus: actual extension + * .musc: header ID */ + if (!check_extensions(sf,"mus,musc")) + goto fail; + if (!is_id32be(0x00,sf, "MUSC")) + goto fail; + + start_offset = read_u32le(0x10,sf); + data_size = read_u32le(0x14,sf); + if (start_offset + data_size != get_streamfile_size(sf)) + goto fail; + /* always does full loops unless it ends in silence */ + loop_flag = read_u32be(get_streamfile_size(sf) - 0x10,sf) != 0x0C000000; + channels = 2; + + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channels, loop_flag); + if (!vgmstream) goto fail; + + vgmstream->sample_rate = read_u16le(0x06,sf); + vgmstream->num_samples = ps_bytes_to_samples(data_size, channels); + vgmstream->loop_start_sample = 0; + vgmstream->loop_end_sample = vgmstream->num_samples; + + vgmstream->meta_type = meta_MUSC; + vgmstream->coding_type = coding_PSX; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = read_u32le(0x18,sf) / 2; + + if (!vgmstream_open_stream(vgmstream, sf, start_offset)) + goto fail; + return vgmstream; +fail: + close_vgmstream(vgmstream); + return NULL; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/riff.c b/Frameworks/vgmstream/vgmstream/src/meta/riff.c index e0b1fda64..c83c48020 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/riff.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/riff.c @@ -279,6 +279,8 @@ static int read_fmt(int big_endian, STREAMFILE* sf, off_t offset, riff_fmt_chunk } default: + /* FFmpeg may play it */ + //vgm_logi("WWISE: unknown codec 0x%04x (report)\n", fmt->format); goto fail; } @@ -418,8 +420,10 @@ VGMSTREAM* init_vgmstream_riff(STREAMFILE* sf) { } /* check for truncated RIFF */ - if (file_size != riff_size + 0x08) + if (file_size != riff_size + 0x08) { + vgm_logi("RIFF: wrong expected size (report/re-rip?)\n"); goto fail; + } /* read through chunks to verify format and find metadata */ { diff --git a/Frameworks/vgmstream/vgmstream/src/meta/smk.c b/Frameworks/vgmstream/vgmstream/src/meta/smk.c index 72113b998..e5b91735a 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/smk.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/smk.c @@ -1,187 +1,192 @@ -#include "meta.h" -#include "../coding/coding.h" -#include "../util.h" - -static int smacker_get_info(STREAMFILE *streamFile, int target_subsong, int * out_total_streams, size_t *out_stream_size, int * out_channel_count, int * out_sample_rate, int * out_num_samples); - -/* SMK - RAD Game Tools Smacker movies (audio/video format) */ -VGMSTREAM * init_vgmstream_smk(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - int channel_count = 0, loop_flag = 0, sample_rate = 0, num_samples = 0; - int total_subsongs = 0, target_subsong = streamFile->stream_index; - size_t stream_size; - - - /* checks */ - if (!check_extensions(streamFile,"smk")) - goto fail; - - if (read_32bitBE(0x00,streamFile) != 0x534D4B32 && /* "SMK2" */ - read_32bitBE(0x00,streamFile) != 0x534D4B34) /* "SMK4" */ - goto fail; - - /* find target stream info */ - if (!smacker_get_info(streamFile, target_subsong, &total_subsongs, &stream_size, &channel_count, &sample_rate, &num_samples)) - goto fail; - - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count, loop_flag); - if (!vgmstream) goto fail; - - vgmstream->layout_type = layout_none; - vgmstream->sample_rate = sample_rate; - vgmstream->num_samples = num_samples; - vgmstream->num_streams = total_subsongs; - vgmstream->stream_size = stream_size; - vgmstream->meta_type = meta_SMACKER; - - { -#ifdef VGM_USE_FFMPEG - /* target_subsong should be passed manually */ - vgmstream->codec_data = init_ffmpeg_header_offset_subsong(streamFile, NULL,0, 0x0,get_streamfile_size(streamFile), target_subsong); - if (!vgmstream->codec_data) goto fail; - vgmstream->coding_type = coding_FFmpeg; -#else - goto fail; -#endif - } - - return vgmstream; - -fail: - close_vgmstream(vgmstream); - return NULL; -} - -typedef enum { - SMK_AUDIO_PACKED = (1<<7), - SMK_AUDIO_PRESENT = (1<<6), - SMK_AUDIO_16BITS = (1<<5), - SMK_AUDIO_STEREO = (1<<4), - SMK_AUDIO_BINK_RDFT = (1<<3), - SMK_AUDIO_BINK_DCT = (1<<2), - //SMK_AUD_UNUSED1 = (1<<1), - //SMK_AUD_UNUSED0 = (1<<0), -} smk_audio_flag; - -//todo test multilang streams and codecs other than SMACKAUD -/* Gets stream info, and number of samples in a file by reading frames - * info: https://wiki.multimedia.cx/index.php/Smacker */ -static int smacker_get_info(STREAMFILE *sf, int target_subsong, int * out_total_subsongs, size_t * out_stream_size, int * out_channel_count, int * out_sample_rate, int * out_num_samples) { - STREAMFILE *sf_index = NULL; - uint32_t flags, total_frames, trees_sizes; - off_t size_offset, type_offset, data_offset; - int i, j, sample_rate = 0, channel_count = 0, num_samples = 0; - int total_subsongs, target_stream = 0; - size_t stream_size = 0; - uint8_t stream_flags = 0; - - - /* rough format: - * - header (id, frames, video info/config, audio info) - * - frame sizes table - * - frame info table - * - huffman trees - * - frame data - */ - - /* read header */ - total_frames = read_u32le(0x0c,sf); - if (total_frames <= 0 || total_frames > 0x100000) goto fail; /* something must be off */ - - flags = read_u32le(0x14,sf); - if (flags & 1) /* extra "ring frame" */ - total_frames += 1; - - trees_sizes = read_u32le(0x34,sf); - - if (target_subsong == 0) target_subsong = 1; - total_subsongs = 0; - for (i = 0; i < 7; i++) { /* up to 7 audio (multilang?) streams */ - uint32_t audio_info = read_u32le(0x48 + 0x04*i,sf); - uint8_t audio_flags = (audio_info >> 24) & 0xFF; - int audio_rate = audio_info & 0x00FFFFFF; - - if (audio_flags & SMK_AUDIO_PRESENT) { - total_subsongs++; - - if (target_subsong == total_subsongs) { - target_stream = i; - sample_rate = audio_rate & 0x00FFFFFF; - channel_count = (audio_flags & SMK_AUDIO_STEREO) ? 2 : 1; - stream_flags = audio_flags; - } - } - } - if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail; - if (sample_rate == 0 || channel_count == 0) goto fail; - - /* read size and type tables into buffer */ - sf_index = reopen_streamfile(sf, total_frames*0x04 + total_frames*0x01); - if (!sf_index) goto fail; - - /* read frames and sum all samples, since some codecs are VBR */ - size_offset = 0x68; - type_offset = size_offset + total_frames*0x04; - data_offset = type_offset + total_frames*0x01 + trees_sizes; - for (i=0; i < total_frames; i++) { - uint32_t frame_size = read_u32le(size_offset,sf_index) & 0xFFFFFFFC; /* last 2 bits are keyframe flags */ - uint8_t frame_type = read_u8 (type_offset,sf_index); /* 0: has palette, 1..7: has stream N) */ - off_t offset = data_offset; - - /* skip palette */ - if (frame_type & (1<<0)) { - uint8_t palette_size = read_u8(offset,sf); - offset += palette_size * 4; - } - - /* read target audio packet and ignore rest (though probably all streams are the same) */ - for (j = 0; j < 7; j++) { - uint32_t audio_size; - - /* check if stream N exists in this frame (supposedly streams can be go in separate frames) */ - if ( !(frame_type & (1<<(j+1))) ) - continue; - - audio_size = read_u32le(offset,sf); - - if (j == target_stream) { - - /* resulting PCM bytes to samples */ - if (stream_flags & SMK_AUDIO_PACKED) { /* Smacker and maybe Bink codecs */ - uint32_t unpacked_size = read_u32le(offset+0x04,sf); - num_samples += unpacked_size / (0x02 * channel_count); - } - else if (stream_flags & SMK_AUDIO_16BITS) { /* PCM16 */ - num_samples += (audio_size - 0x04) / (0x02 * channel_count); - } - else { /* PCM8 */ - num_samples += (audio_size - 0x04) / (0x01 * channel_count); - } - } - - stream_size += audio_size; - offset += audio_size; - } - - /* rest is video packet (size = offset - data_offset) */ - - size_offset += 0x04; - type_offset += 0x01; - data_offset += frame_size; - } - - if (out_total_subsongs) *out_total_subsongs = total_subsongs; - if (out_stream_size) *out_stream_size = stream_size; - if (out_sample_rate) *out_sample_rate = sample_rate; - if (out_channel_count) *out_channel_count = channel_count; - if (out_num_samples) *out_num_samples = num_samples; - - close_streamfile(sf_index); - return 1; - -fail: - close_streamfile(sf_index); - return 0; -} +#include "meta.h" +#include "../coding/coding.h" +#include "../util.h" + +static int smacker_get_info(STREAMFILE* sf, int target_subsong, int* p_total_subsongs, size_t* p_stream_size, int* p_channels, int* p_sample_rate, int* p_num_samples); + +/* SMK - RAD Game Tools older Smacker movies (audio/video format) */ +VGMSTREAM* init_vgmstream_smk(STREAMFILE *sf) { + VGMSTREAM* vgmstream = NULL; + int channels = 0, loop_flag = 0, sample_rate = 0, num_samples = 0; + int total_subsongs = 0, target_subsong = sf->stream_index; + size_t stream_size; + + + /* checks */ + if (!check_extensions(sf,"smk")) + goto fail; + + if (!is_id32be(0x00,sf, "SMK2") && + !is_id32be(0x00,sf, "SMK4")) + goto fail; + + /* find target stream info */ + if (!smacker_get_info(sf, target_subsong, &total_subsongs, &stream_size, &channels, &sample_rate, &num_samples)) + goto fail; + + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channels, loop_flag); + if (!vgmstream) goto fail; + + vgmstream->meta_type = meta_SMACKER; + vgmstream->sample_rate = sample_rate; + vgmstream->num_samples = num_samples; + + vgmstream->num_streams = total_subsongs; + vgmstream->stream_size = stream_size; + + { +#ifdef VGM_USE_FFMPEG + /* target_subsong should be passed manually */ + vgmstream->codec_data = init_ffmpeg_header_offset_subsong(sf, NULL,0, 0x00, 0, target_subsong); + if (!vgmstream->codec_data) goto fail; + vgmstream->coding_type = coding_FFmpeg; + vgmstream->layout_type = layout_none; +#else + goto fail; +#endif + } + + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} + +typedef enum { + SMK_AUDIO_PACKED = (1<<7), + SMK_AUDIO_PRESENT = (1<<6), + SMK_AUDIO_16BITS = (1<<5), + SMK_AUDIO_STEREO = (1<<4), + SMK_AUDIO_BINK_RDFT = (1<<3), + SMK_AUDIO_BINK_DCT = (1<<2), + //SMK_AUD_UNUSED1 = (1<<1), + //SMK_AUD_UNUSED0 = (1<<0), +} smk_audio_flag; + +//todo test multilang streams and codecs other than SMACKAUD +/* Gets stream info, and number of samples in a file by reading frames + * info: https://wiki.multimedia.cx/index.php/Smacker */ +static int smacker_get_info(STREAMFILE* sf, int target_subsong, int* out_total_subsongs, size_t* p_stream_size, int* p_channels, int* p_sample_rate, int* p_num_samples) { + STREAMFILE* sf_index = NULL; + uint32_t flags, total_frames, trees_sizes; + off_t size_offset, type_offset, data_offset; + int i, j, sample_rate = 0, channels = 0, num_samples = 0; + int total_subsongs, target_stream = 0; + size_t stream_size = 0; + uint8_t stream_flags = 0; + + + /* rough format: + * - header (id, frames, video info/config, audio info) + * - frame sizes table + * - frame info table + * - huffman trees + * - frame data + */ + + /* read header */ + total_frames = read_u32le(0x0c,sf); + if (total_frames <= 0 || total_frames > 0x100000) goto fail; /* something must be off */ + + flags = read_u32le(0x14,sf); + if (flags & 1) /* extra "ring frame" */ + total_frames += 1; + + trees_sizes = read_u32le(0x34,sf); + + if (target_subsong == 0) target_subsong = 1; + total_subsongs = 0; + for (i = 0; i < 7; i++) { /* up to 7 audio (multilang?) streams */ + uint32_t audio_info = read_u32le(0x48 + 0x04*i,sf); + uint8_t audio_flags = (audio_info >> 24) & 0xFF; + int audio_rate = audio_info & 0x00FFFFFF; + + if (audio_flags & SMK_AUDIO_PRESENT) { + total_subsongs++; + + if (target_subsong == total_subsongs) { + target_stream = i; + sample_rate = audio_rate & 0x00FFFFFF; + channels = (audio_flags & SMK_AUDIO_STEREO) ? 2 : 1; + stream_flags = audio_flags; + } + } + } + if (total_subsongs < 1) { + vgm_logi("SMK: no audio in movie (ignore)\n"); + goto fail; + } + if (target_subsong < 0 || target_subsong > total_subsongs) goto fail; + if (sample_rate == 0 || channels == 0) goto fail; + + /* read size and type tables into buffer */ + sf_index = reopen_streamfile(sf, total_frames*0x04 + total_frames*0x01); + if (!sf_index) goto fail; + + /* read frames and sum all samples, since some codecs are VBR */ + size_offset = 0x68; + type_offset = size_offset + total_frames*0x04; + data_offset = type_offset + total_frames*0x01 + trees_sizes; + for (i = 0; i < total_frames; i++) { + uint32_t frame_size = read_u32le(size_offset,sf_index) & 0xFFFFFFFC; /* last 2 bits are keyframe flags */ + uint8_t frame_type = read_u8 (type_offset,sf_index); /* 0: has palette, 1..7: has stream N) */ + off_t offset = data_offset; + + /* skip palette */ + if (frame_type & (1<<0)) { + uint8_t palette_size = read_u8(offset,sf); + offset += palette_size * 4; + } + + /* read target audio packet and ignore rest (though probably all streams are the same) */ + for (j = 0; j < 7; j++) { + uint32_t audio_size; + + /* check if stream N exists in this frame (supposedly streams can be go in separate frames) */ + if ( !(frame_type & (1<<(j+1))) ) + continue; + + audio_size = read_u32le(offset,sf); + + if (j == target_stream) { + + /* resulting PCM bytes to samples */ + if (stream_flags & SMK_AUDIO_PACKED) { /* Smacker and maybe Bink codecs */ + uint32_t unpacked_size = read_u32le(offset+0x04,sf); + num_samples += unpacked_size / (0x02 * channels); + } + else if (stream_flags & SMK_AUDIO_16BITS) { /* PCM16 */ + num_samples += (audio_size - 0x04) / (0x02 * channels); + } + else { /* PCM8 */ + num_samples += (audio_size - 0x04) / (0x01 * channels); + } + } + + stream_size += audio_size; + offset += audio_size; + } + + /* rest is video packet (size = offset - data_offset) */ + + size_offset += 0x04; + type_offset += 0x01; + data_offset += frame_size; + } + + if (out_total_subsongs) *out_total_subsongs = total_subsongs; + if (p_stream_size) *p_stream_size = stream_size; + if (p_sample_rate) *p_sample_rate = sample_rate; + if (p_channels) *p_channels = channels; + if (p_num_samples) *p_num_samples = num_samples; + + close_streamfile(sf_index); + return 1; + +fail: + close_streamfile(sf_index); + return 0; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/sqex_scd.c b/Frameworks/vgmstream/vgmstream/src/meta/sqex_scd.c index acc012fd6..83be3944f 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/sqex_scd.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/sqex_scd.c @@ -100,8 +100,12 @@ VGMSTREAM* init_vgmstream_sqex_scd(STREAMFILE* sf) { target_entry = i; } } - if (meta_offset == 0) goto fail; + /* SCD can contain 0 entries too */ + if (meta_offset == 0) { + vgm_logi("SQEX SCD: bank has no subsongs (ignore)\n"); + goto fail; + } } /** stream header **/ diff --git a/Frameworks/vgmstream/vgmstream/src/meta/sqex_sead.c b/Frameworks/vgmstream/vgmstream/src/meta/sqex_sead.c index 6a4a75c85..651b7cf35 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/sqex_sead.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/sqex_sead.c @@ -765,7 +765,7 @@ static void parse_sead_sab_name(sead_header *sead, STREAMFILE *sf) { } -static int parse_sead(sead_header *sead, STREAMFILE *sf) { +static int parse_sead(sead_header* sead, STREAMFILE* sf) { uint32_t (*read_u32)(off_t,STREAMFILE*) = sead->big_endian ? read_u32be : read_u32le; uint16_t (*read_u16)(off_t,STREAMFILE*) = sead->big_endian ? read_u16be : read_u16le; @@ -856,8 +856,10 @@ static int parse_sead(sead_header *sead, STREAMFILE *sf) { } /* SAB can contain 0 entries too */ - if (sead->mtrl_offset == 0) + if (sead->mtrl_offset == 0) { + vgm_logi("SQEX SEAD: bank has no subsongs (ignore)\n"); goto fail; + } } /** stream header **/ diff --git a/Frameworks/vgmstream/vgmstream/src/meta/txth.c b/Frameworks/vgmstream/vgmstream/src/meta/txth.c index 84c60aa21..668ad6cea 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/txth.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/txth.c @@ -40,12 +40,14 @@ typedef enum { ASF = 30, /* Argonaut ASF 4-bit ADPCM */ EAXA = 31, /* Electronic Arts EA-XA 4-bit ADPCM v1 */ OKI4S = 32, /* OKI ADPCM with 16-bit output (unlike OKI/VOX/Dialogic ADPCM's 12-bit) */ -} txth_type; + + UNKNOWN = 99, +} txth_codec_t; typedef enum { DEFAULT, NEGATIVE, POSITIVE, INVERTED } txth_loop_t; typedef struct { - txth_type codec; + txth_codec_t codec; uint32_t codec_mode; uint32_t value_mul; @@ -196,6 +198,25 @@ VGMSTREAM* init_vgmstream_txth(STREAMFILE* sf) { } + /* set common interleaves to simplify usage + * (maybe should ignore if manually overwritten, possibly with 0 on purpose?) */ + if (txth.interleave == 0) { + uint32_t interleave = 0; + switch(txth.codec) { + case PSX: interleave = 0x10; break; + case PSX_bf: interleave = 0x10; break; + case NGC_DSP: interleave = 0x08; break; + case PCM16LE: interleave = 0x02; break; + case PCM16BE: interleave = 0x02; break; + case PCM8: interleave = 0x01; break; + case PCM8_U: interleave = 0x01; break; + default: + break; + } + txth.interleave = interleave; + } + + /* type to coding conversion */ switch (txth.codec) { case PSX: coding = coding_PSX; break; @@ -881,63 +902,61 @@ fail: return 0; } +static txth_codec_t parse_codec(txth_header* txth, const char* val) { + if (is_string(val,"PSX")) return PSX; + else if (is_string(val,"XBOX")) return XBOX; + else if (is_string(val,"NGC_DTK")) return NGC_DTK; + else if (is_string(val,"DTK")) return NGC_DTK; + else if (is_string(val,"PCM16BE")) return PCM16BE; + else if (is_string(val,"PCM16LE")) return PCM16LE; + else if (is_string(val,"PCM8")) return PCM8; + else if (is_string(val,"SDX2")) return SDX2; + else if (is_string(val,"DVI_IMA")) return DVI_IMA; + else if (is_string(val,"MPEG")) return MPEG; + else if (is_string(val,"IMA")) return IMA; + else if (is_string(val,"AICA")) return AICA; + else if (is_string(val,"MSADPCM")) return MSADPCM; + else if (is_string(val,"NGC_DSP")) return NGC_DSP; + else if (is_string(val,"DSP")) return NGC_DSP; + else if (is_string(val,"PCM8_U_int")) return PCM8_U_int; + else if (is_string(val,"PSX_bf")) return PSX_bf; + else if (is_string(val,"MS_IMA")) return MS_IMA; + else if (is_string(val,"PCM8_U")) return PCM8_U; + else if (is_string(val,"APPLE_IMA4")) return APPLE_IMA4; + else if (is_string(val,"ATRAC3")) return ATRAC3; + else if (is_string(val,"ATRAC3PLUS")) return ATRAC3PLUS; + else if (is_string(val,"XMA1")) return XMA1; + else if (is_string(val,"XMA2")) return XMA2; + else if (is_string(val,"FFMPEG")) return FFMPEG; + else if (is_string(val,"AC3")) return AC3; + else if (is_string(val,"PCFX")) return PCFX; + else if (is_string(val,"PCM4")) return PCM4; + else if (is_string(val,"PCM4_U")) return PCM4_U; + else if (is_string(val,"OKI16")) return OKI16; + else if (is_string(val,"OKI4S")) return OKI4S; + else if (is_string(val,"AAC")) return AAC; + else if (is_string(val,"TGC")) return TGC; + else if (is_string(val,"GCOM_ADPCM")) return TGC; + else if (is_string(val,"ASF")) return ASF; + else if (is_string(val,"EAXA")) return EAXA; + /* special handling */ + else if (is_string(val,"name_value")) return txth->name_values[0]; + else if (is_string(val,"name_value1")) return txth->name_values[0]; + else if (is_string(val,"name_value2")) return txth->name_values[1]; + else if (is_string(val,"name_value3")) return txth->name_values[2]; + //todo rest (handle in function) + + return UNKNOWN; +} + static int parse_keyval(STREAMFILE* sf_, txth_header* txth, const char* key, char* val) { //;VGM_LOG("TXTH: key=%s, val=%s\n", key, val); /* CODEC */ if (is_string(key,"codec")) { - if (is_string(val,"PSX")) txth->codec = PSX; - else if (is_string(val,"XBOX")) txth->codec = XBOX; - else if (is_string(val,"NGC_DTK")) txth->codec = NGC_DTK; - else if (is_string(val,"DTK")) txth->codec = NGC_DTK; - else if (is_string(val,"PCM16BE")) txth->codec = PCM16BE; - else if (is_string(val,"PCM16LE")) txth->codec = PCM16LE; - else if (is_string(val,"PCM8")) txth->codec = PCM8; - else if (is_string(val,"SDX2")) txth->codec = SDX2; - else if (is_string(val,"DVI_IMA")) txth->codec = DVI_IMA; - else if (is_string(val,"MPEG")) txth->codec = MPEG; - else if (is_string(val,"IMA")) txth->codec = IMA; - else if (is_string(val,"AICA")) txth->codec = AICA; - else if (is_string(val,"MSADPCM")) txth->codec = MSADPCM; - else if (is_string(val,"NGC_DSP")) txth->codec = NGC_DSP; - else if (is_string(val,"DSP")) txth->codec = NGC_DSP; - else if (is_string(val,"PCM8_U_int")) txth->codec = PCM8_U_int; - else if (is_string(val,"PSX_bf")) txth->codec = PSX_bf; - else if (is_string(val,"MS_IMA")) txth->codec = MS_IMA; - else if (is_string(val,"PCM8_U")) txth->codec = PCM8_U; - else if (is_string(val,"APPLE_IMA4")) txth->codec = APPLE_IMA4; - else if (is_string(val,"ATRAC3")) txth->codec = ATRAC3; - else if (is_string(val,"ATRAC3PLUS")) txth->codec = ATRAC3PLUS; - else if (is_string(val,"XMA1")) txth->codec = XMA1; - else if (is_string(val,"XMA2")) txth->codec = XMA2; - else if (is_string(val,"FFMPEG")) txth->codec = FFMPEG; - else if (is_string(val,"AC3")) txth->codec = AC3; - else if (is_string(val,"PCFX")) txth->codec = PCFX; - else if (is_string(val,"PCM4")) txth->codec = PCM4; - else if (is_string(val,"PCM4_U")) txth->codec = PCM4_U; - else if (is_string(val,"OKI16")) txth->codec = OKI16; - else if (is_string(val,"OKI4S")) txth->codec = OKI4S; - else if (is_string(val,"AAC")) txth->codec = AAC; - else if (is_string(val,"TGC")) txth->codec = TGC; - else if (is_string(val,"GCOM_ADPCM")) txth->codec = TGC; - else if (is_string(val,"ASF")) txth->codec = ASF; - else if (is_string(val,"EAXA")) txth->codec = EAXA; - else goto fail; - - /* set common interleaves to simplify usage - * (do it here to in case it's overwritten later, possibly with 0 on purpose) */ - if (txth->interleave == 0) { - switch(txth->codec) { - case PSX: txth->interleave = 0x10; break; - case PSX_bf: txth->interleave = 0x10; break; - case NGC_DSP: txth->interleave = 0x08; break; - case PCM16LE: txth->interleave = 0x02; break; - case PCM16BE: txth->interleave = 0x02; break; - case PCM8: txth->interleave = 0x01; break; - case PCM8_U: txth->interleave = 0x01; break; - default: break; - } - } + txth->codec = parse_codec(txth, val); + if (txth->codec == UNKNOWN) + goto fail; } else if (is_string(key,"codec_mode")) { if (!parse_num(txth->sf_head,txth,val, &txth->codec_mode)) goto fail; @@ -1372,7 +1391,7 @@ static int parse_keyval(STREAMFILE* sf_, txth_header* txth, const char* key, cha return 1; fail: - VGM_LOG("TXTH: error parsing key=%s, val=%s\n", key, val); + vgm_logi("TXTH: error parsing key=%s, val=%s\n", key, val); return 0; } @@ -1589,6 +1608,26 @@ static int read_name_table_keyval(txth_header* txth, const char* line, char* key return 0; } +static int parse_name_val(txth_header* txth, char* subval) { + int ok; + + ok = parse_num(txth->sf_head, txth, subval, &txth->name_values[txth->name_values_count]); + if (!ok) { + /* in rare cases may set codec */ + txth_codec_t codec = parse_codec(txth, subval); + if (codec == UNKNOWN) + goto fail; + txth->name_values[txth->name_values_count] = codec; + } + txth->name_values_count++; + if (txth->name_values_count >= 16) /* surely nobody needs that many */ + goto fail; + + return 1; +fail: + return 0; +} + static int parse_name_table(txth_header* txth, char* name_list) { STREAMFILE* sf_names = NULL; off_t txt_offset, file_size; @@ -1666,9 +1705,7 @@ static int parse_name_table(txth_header* txth, char* name_list) { if (current[0] == ',') current++; - if (!parse_num(txth->sf_head,txth,subval, &txth->name_values[txth->name_values_count])) goto fail; - txth->name_values_count++; - if (txth->name_values_count >= 16) /* surely nobody needs that many */ + if (!parse_name_val(txth, subval)) goto fail; } @@ -1806,7 +1843,7 @@ static int parse_num(STREAMFILE* sf, txth_header* txth, const char* val, uint32_ offset += txth->base_offset; if (/*offset < 0 ||*/ offset > get_streamfile_size(sf)) { - VGM_LOG("TXTH: wrong offset %x + %x\n", offset - txth->base_offset, txth->base_offset); + vgm_logi("TXTH: wrong offset over file size (%x + %x)\n", offset - txth->base_offset, txth->base_offset); goto fail; } @@ -1920,7 +1957,7 @@ static int parse_num(STREAMFILE* sf, txth_header* txth, const char* val, uint32_ //;VGM_LOG("TXTH: final result %u (0x%x)\n", result, result); return 1; fail: - VGM_LOG("TXTH: error parsing num '%s'\n", val); + //VGM_LOG("TXTH: error parsing num '%s'\n", val); return 0; } diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ubi_bao.c b/Frameworks/vgmstream/vgmstream/src/meta/ubi_bao.c index 3268bab0d..401a53ef0 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ubi_bao.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ubi_bao.c @@ -634,7 +634,7 @@ static VGMSTREAM* init_vgmstream_ubi_bao_header(ubi_bao_header* bao, STREAMFILE* VGMSTREAM* vgmstream = NULL; if (bao->total_subsongs <= 0) { - VGM_LOG("UBI BAO: no subsongs\n"); + vgm_logi("UBI BAO: bank has no subsongs (ignore)\n"); goto fail; /* not uncommon */ } @@ -1473,7 +1473,10 @@ static STREAMFILE* setup_bao_streamfile(ubi_bao_header* bao, STREAMFILE* sf) { if (bao->stream_size - bao->prefetch_size != 0) { new_sf = open_streamfile_by_filename(sf, bao->resource_name); - if (!new_sf) { VGM_LOG("UBI BAO: external stream '%s' not found\n", bao->resource_name); goto fail; } + if (!new_sf) { + vgm_logi("UBI BAO: external file '%s' not found (put together)\n", bao->resource_name); + goto fail; + } stream_segments[1] = new_sf; new_sf = open_clamp_streamfile(stream_segments[1], bao->stream_offset, (bao->stream_size - bao->prefetch_size)); @@ -1495,7 +1498,10 @@ static STREAMFILE* setup_bao_streamfile(ubi_bao_header* bao, STREAMFILE* sf) { } else if (bao->is_external) { new_sf = open_streamfile_by_filename(sf, bao->resource_name); - if (!new_sf) { VGM_LOG("UBI BAO: external stream '%s' not found\n", bao->resource_name); goto fail; } + if (!new_sf) { + vgm_logi("UBI BAO: external file '%s' not found (put together)\n", bao->resource_name); + goto fail; + } temp_sf = new_sf; new_sf = open_clamp_streamfile(temp_sf, bao->stream_offset, bao->stream_size); @@ -1884,11 +1890,10 @@ static int config_bao_version(ubi_bao_header* bao, STREAMFILE* sf) { * - 0x94: stream id? 0x9C: extra size */ case 0x002A0300: /* Watch Dogs (Wii U) */ /* similar to SC:B */ - default: /* others possibly using BAO: Just Dance, Watch_Dogs, Far Cry Primal, Far Cry 4 */ - VGM_LOG("UBI BAO: unknown BAO version %08x\n", bao->version); + default: /* others possibly using BAO: Watch_Dogs, Far Cry Primal, Far Cry 4 */ + vgm_logi("UBI BAO: unknown BAO version %08x\n", bao->version); return 0; } - VGM_LOG("UBI BAO: unknown BAO version %08x\n", bao->version); return 0; } diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ubi_sb.c b/Frameworks/vgmstream/vgmstream/src/meta/ubi_sb.c index d63a0845b..4820f028f 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ubi_sb.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ubi_sb.c @@ -644,7 +644,7 @@ static VGMSTREAM *init_vgmstream_ubi_dat_main(ubi_sb_header *sb, STREAMFILE *sf_ sf_data = open_streamfile_by_filename(sf, sb->resource_name); if (!sf_data) { /* play silence if external file is not found since Rayman 2 seems to rely on this behavior */ - VGM_LOG("UBI DAT: external stream '%s' not found\n", sb->resource_name); + vgm_logi("UBI DAT: external file '%s' not found (put together)\n", sb->resource_name); strncat(sb->readable_name, " (missing)", sizeof(sb->readable_name)); sb->duration = (float)pcm_bytes_to_samples(sb->stream_size, sb->channels, 16) / (float)sb->sample_rate; return init_vgmstream_ubi_sb_silence(sb); @@ -1301,10 +1301,11 @@ static VGMSTREAM* init_vgmstream_ubi_sb_audio(ubi_sb_header* sb, STREAMFILE* sf_ if (sb->is_external) { sf_data = open_streamfile_by_filename(sf, sb->resource_name); if (sf_data == NULL) { - VGM_LOG("UBI SB: external stream '%s' not found\n", sb->resource_name); + vgm_logi("UBI SB: external file '%s' not found (put together)\n", sb->resource_name); goto fail; } - } else { + } + else { sf_data = sf; } @@ -1341,7 +1342,7 @@ static VGMSTREAM* init_vgmstream_ubi_sb_layer(ubi_sb_header* sb, STREAMFILE* sf_ if (sb->is_external) { sf_data = open_streamfile_by_filename(sf,sb->resource_name); if (sf_data == NULL) { - VGM_LOG("UBI SB: external stream '%s' not found\n", sb->resource_name); + vgm_logi("UBI SB: external file '%s' not found (put together)\n", sb->resource_name); goto fail; } } @@ -1563,7 +1564,7 @@ static VGMSTREAM* init_vgmstream_ubi_sb_header(ubi_sb_header* sb, STREAMFILE* sf VGMSTREAM* vgmstream = NULL; if (sb->total_subsongs == 0) { - VGM_LOG("UBI SB: no subsongs\n"); + vgm_logi("UBI SB: bank has no subsongs (ignore)\n"); goto fail; } @@ -1862,8 +1863,8 @@ static int parse_type_audio(ubi_sb_header* sb, off_t offset, STREAMFILE* sf) { /* PC can have subblock 2 based on two fields near the end but it wasn't seen so far */ /* stream_type field is not used if the flag is not set (it even contains garbage in some versions) - * except for PS3 which has two hardware codecs (PSX and AT3) */ - if (!software_flag && sb->platform != UBI_PS3) + * except for PS3 and new PSP which have two hardware codecs (PSX and AT3) */ + if (!software_flag && sb->platform != UBI_PS3 && !(sb->platform == UBI_PSP && !sb->is_psp_old)) sb->stream_type = 0x00; } else { sb->subblock_id = (sb->stream_type == 0x01) ? 0 : 1; @@ -4042,6 +4043,6 @@ static int config_sb_version(ubi_sb_header* sb, STREAMFILE* sf) { return 1; } - VGM_LOG("UBI SB: unknown SB/SM version+platform %08x\n", sb->version); + vgm_logi("UBI SB: unknown SB/SM version+platform %08x (report)\n", sb->version); return 0; } diff --git a/Frameworks/vgmstream/vgmstream/src/meta/wii_bns.c b/Frameworks/vgmstream/vgmstream/src/meta/wii_bns.c index aa4b086f2..12fc35c3c 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/wii_bns.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/wii_bns.c @@ -8,7 +8,7 @@ VGMSTREAM* init_vgmstream_wii_bns(STREAMFILE* sf) { off_t bns_offset; uint32_t info_offset = 0, data_offset = 0; uint32_t channel_info_offset_list_offset; - int channels, loop_flag, sample_rate; + int channels, loop_flag, sample_rate; uint32_t sample_count, loop_start; /* checks */ @@ -106,7 +106,7 @@ VGMSTREAM* init_vgmstream_wii_bns(STREAMFILE* sf) { channel_info_offset_list_offset = info_offset + read_u32be(info_offset+0x10,sf); } - /* build the VGMSTREAM */ + /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channels, loop_flag); if (!vgmstream) goto fail; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/wwise.c b/Frameworks/vgmstream/vgmstream/src/meta/wwise.c index e41aa33d7..d48a6315b 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/wwise.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/wwise.c @@ -510,7 +510,7 @@ VGMSTREAM* init_vgmstream_wwise(STREAMFILE* sf) { if (ww.bits_per_sample != 16) goto fail; /* original data_size doesn't look related to samples or anything */ - ww.data_size = ww.file_size - ww.data_offset; + ww.data_size = ww.file_size - ww.data_offset; vgmstream->codec_data = init_ffmpeg_offset(sf, ww.data_offset, ww.data_size); if (!vgmstream->codec_data) goto fail; @@ -592,8 +592,8 @@ VGMSTREAM* init_vgmstream_wwise(STREAMFILE* sf) { vgmstream->layout_type = layout_none; break; } - #endif + case HEVAG: /* PSV */ /* changed values, another bizarre Wwise quirk */ //ww.block_align /* unknown (1ch=2, 2ch=4) */ @@ -644,6 +644,7 @@ VGMSTREAM* init_vgmstream_wwise(STREAMFILE* sf) { break; } #endif + case PTADPCM: /* newer ADPCM [Bayonetta 2 (Switch), Genshin Impact (PC)] */ if (ww.bits_per_sample != 4) goto fail; if (ww.block_align != 0x24 * ww.channels && ww.block_align != 0x104 * ww.channels) goto fail; @@ -681,7 +682,7 @@ static int is_dsp_full_interleave(STREAMFILE* sf, wwise_header* ww, off_t coef_o * - .bnk would be memory banks = full * - otherwise small-ish sizes, stereo, with initial predictors for the * second channel matching half size = full - * some files aren't detectable like this though, when predictors are 0 + * some files aren't detectable like this though, when predictors are 0 * (but since memory wem aren't that used this shouldn't be too common) */ if (ww->truncated) @@ -885,6 +886,7 @@ static int parse_wwise(STREAMFILE* sf, wwise_header* ww) { case 0x3041: ww->codec = OPUSWW; break; /* "OPUS_WEM", added on Wwise 2019.2.3, replaces OPUS */ case 0x8311: ww->codec = PTADPCM; break; /* added on Wwise 2019.1, replaces IMA */ default: + vgm_logi("WWISE: unknown codec 0x%04x (report)\n", ww->format); goto fail; } @@ -893,11 +895,14 @@ static int parse_wwise(STREAMFILE* sf, wwise_header* ww) { if (ww->extra_size == 0x0c + ww->channels * 0x2e) { /* newer Wwise DSP with coefs [Epic Mickey 2 (Wii), Batman Arkham Origins Blackgate (3DS)] */ ww->codec = DSP; - } else if (ww->extra_size == 0x0a && ww->wiih_offset) { /* WiiH */ + } + else if (ww->extra_size == 0x0a && ww->wiih_offset) { /* WiiH */ /* few older Wwise DSP with num_samples in extra_size [Tony Hawk: Shred (Wii)] */ ww->codec = DSP; - } else if (ww->block_align == 0x104 * ww->channels) { - ww->codec = PTADPCM; /* Bayonetta 2 (Switch) */ + } + else if (ww->block_align == 0x104 * ww->channels) { + /* Bayonetta 2 (Switch) */ + ww->codec = PTADPCM; } } @@ -911,7 +916,7 @@ static int parse_wwise(STREAMFILE* sf, wwise_header* ww) { /* catch wrong rips as truncated tracks' file_size should be much smaller than data_size, * but it's possible to pre-fetch small files too [Punch Out!! (Wii)] */ if (ww->data_offset + ww->data_size - ww->file_size < 0x5000 && ww->file_size > 0x10000) { - VGM_LOG("WWISE: wrong expected data_size\n"); + vgm_logi("WWISE: wrong expected size (re-rip?)\n"); goto fail; } @@ -919,7 +924,7 @@ static int parse_wwise(STREAMFILE* sf, wwise_header* ww) { ww->codec == OPUSNX || ww->codec == OPUS || ww->codec == OPUSWW || ww->codec == PTADPCM) { ww->truncated = 1; /* only seen those, probably all exist (XWMA, AAC, HEVAG, ATRAC9?) */ } else { - VGM_LOG("WWISE: wrong size, maybe truncated\n"); + vgm_logi("WWISE: wrong expected size, maybe truncated (report)\n"); goto fail; } } @@ -955,7 +960,7 @@ fail: 0x14 (4): LoopInfo.dwLoopEndPacketOffset? 0x18 (4): dwSeekTableSize (0 = no seek table) 0x1c (4): dwVorbisDataOffset (offset within data) -0x20 (2): uMaxPacketSize (not including header) +0x20 (2): uMaxPacketSize (not including header) 0x22 (2): uLastGranuleExtra (0..~0x100) 0x24 (4): dwDecodeAllocSize (0~0x5000) 0x28 (4): dwDecodeX64AllocSize (mid, 0~0x5000) @@ -971,7 +976,7 @@ fail: 0x0c (2): ? (small, 0..~0x400) [(4) when size is 0x2C] 0x10 (4): dwSeekTableSize (0 = no seek table) 0x14 (4): dwVorbisDataOffset (offset within data) -0x18 (2): uMaxPacketSize (not including header) +0x18 (2): uMaxPacketSize (not including header) 0x1a (2): uLastGranuleExtra (0..~0x100) [(4) when size is 0x2C] 0x1c (4): dwDecodeAllocSize (0~0x5000) 0x20 (4): dwDecodeX64AllocSize (0~0x5000) @@ -988,7 +993,7 @@ fail: 0x26 (2): LoopInfo.uLoopEndExtra (extra samples after seek?) 0x28 (4): dwSeekTableSize (0 = no seek table) 0x2c (4): dwVorbisDataOffset (offset within data) -0x30 (2): uMaxPacketSize (not including header) +0x30 (2): uMaxPacketSize (not including header) 0x32 (2): uLastGranuleExtra (small, 0..~0x100) 0x34 (4): dwDecodeAllocSize (mid, 0~0x5000) 0x38 (4): dwDecodeX64AllocSize (mid, 0~0x5000) diff --git a/Frameworks/vgmstream/vgmstream/src/meta/xnb_lz4mg.h b/Frameworks/vgmstream/vgmstream/src/meta/xnb_lz4mg.h index f783fa593..dc61510d0 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/xnb_lz4mg.h +++ b/Frameworks/vgmstream/vgmstream/src/meta/xnb_lz4mg.h @@ -190,7 +190,7 @@ static int lz4mg_decompress(lz4mg_stream_t* strm) { default: goto fail; } - } + } buffer_end: strm->next_out += dst_pos; @@ -208,16 +208,16 @@ fail: #if 0 /* non-streamed form for reference, assumes buffers are big enough */ static void decompress_lz4mg(uint8_t* dst, size_t dst_size, const uint8_t* src, size_t src_size) { - size_t src_pos = 0; - size_t dst_pos = 0; + size_t src_pos = 0; + size_t dst_pos = 0; uint8_t token; int literal_len, match_len, next_len; int match_pos, match_offset; int i; - while (src_pos < src_size && dst_pos < dst_size) { + while (src_pos < src_size && dst_pos < dst_size) { - token = src[src_pos++]; + token = src[src_pos++]; if (src_pos > src_size) break; @@ -259,7 +259,7 @@ static void decompress_lz4mg(uint8_t* dst, size_t dst_size, const uint8_t* src, for(i = 0; i < match_len; i++) { dst[dst_pos++] = dst[match_pos++]; /* note RLE with short offsets */ } - } + } } #endif diff --git a/Frameworks/vgmstream/vgmstream/src/meta/xsh_xsd_xss.c b/Frameworks/vgmstream/vgmstream/src/meta/xsh_xsd_xss.c index 2c7dfc48b..4e9a80e0a 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/xsh_xsd_xss.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/xsh_xsd_xss.c @@ -2,7 +2,7 @@ #include "../coding/coding.h" -/* XSH+XSD/XSS - from Treyarch games [Spider-Man 2002 (Xbox), Kelly Slater's Pro Surfer (Xbox)] */ +/* XSH+XSD/XSS - from Treyarch games */ VGMSTREAM* init_vgmstream_xsh_xsd_xss(STREAMFILE* sf) { VGMSTREAM* vgmstream = NULL; STREAMFILE* sf_body = NULL; @@ -30,34 +30,47 @@ VGMSTREAM* init_vgmstream_xsh_xsd_xss(STREAMFILE* sf) { if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail; switch(version) { - case 0x009D: + case 0x009D: /* Spider-Man 2002 (Xbox) */ offset = 0x0c + (target_subsong-1) * 0x60; name_offset = offset + 0x00; name_size = 0x20; - stream_type = read_u32le(offset + 0x20,sf); - stream_offset = read_u32le(offset + 0x24,sf); - stream_size = read_u32le(offset + 0x28,sf); - flags = read_u32le(offset + 0x34,sf); - /* 0x38: flags? */ + offset += 0x20; + + stream_type = read_u32le(offset + 0x00,sf); + stream_offset = read_u32le(offset + 0x04,sf); + stream_size = read_u32le(offset + 0x08,sf); + flags = read_u32le(offset + 0x14,sf); + /* 0x18: flags? */ num_samples = 0; - offset = offset + 0x3c; + offset += 0x1c; break; - case 0x0100: - offset = 0x0c + (target_subsong-1) * 0x64; + case 0x0100: /* Kelly Slater's Pro Surfer (Xbox) */ + case 0x0101: /* Minority Report: Everybody Runs (Xbox), NHL 2K3 (Xbox) */ + /* NHL has stream IDs instead of names */ + if (read_u32le(0x0c,sf) > 0x1000) { + offset = 0x0c + (target_subsong-1) * 0x64; + name_offset = offset + 0x00; + name_size = 0x20; + offset += 0x20; + } + else { + offset = 0x0c + (target_subsong-1) * 0x48; + name_offset = offset + 0x00; + name_size = 0x00; + offset += 0x04; + } - name_offset = offset + 0x00; - name_size = 0x20; - stream_type = read_u32le(offset + 0x20,sf); - stream_offset = read_u32le(offset + 0x24,sf); - stream_size = read_u32le(offset + 0x28,sf); - flags = read_u32le(offset + 0x34,sf); - num_samples = read_u32le(offset + 0x38,sf); - /* 0x3c: flags? */ + stream_type = read_u32le(offset + 0x00,sf); + stream_offset = read_u32le(offset + 0x04,sf); + stream_size = read_u32le(offset + 0x08,sf); + flags = read_u32le(offset + 0x14,sf); + num_samples = read_u32le(offset + 0x18,sf); + /* 0x1c: flags? */ - offset = offset + 0x40; + offset += 0x20; break; default: @@ -90,13 +103,13 @@ VGMSTREAM* init_vgmstream_xsh_xsd_xss(STREAMFILE* sf) { char filename[255]; switch (version) { case 0x009D: - /* stream is a named .xss, with stream_offset/size = 0 (Spider-Man) */ + /* stream is a named .xss, with stream_offset/size = 0 */ read_string(filename, name_size, name_offset,sf); strcat(filename, ".xss"); sf_body = open_streamfile_by_filename(sf,filename); if (!sf_body) { - VGM_LOG("XSH: can't find %s\n", filename); + vgm_logi("XSH: external file '%s' not found (put together)\n", filename); goto fail; } @@ -112,11 +125,12 @@ VGMSTREAM* init_vgmstream_xsh_xsd_xss(STREAMFILE* sf) { //break; case 0x0100: - /* bigfile with all streams (Kelly Slater) */ + case 0x0101: + /* bigfile with all streams */ snprintf(filename, sizeof(filename), "%s", "STREAMS.XSS"); sf_body = open_streamfile_by_filename(sf,filename); if (!sf_body) { - VGM_LOG("XSH: can't find %s\n", filename); + vgm_logi("XSH: external file '%s' not found (put together)\n", filename); goto fail; } break; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/xvag.c b/Frameworks/vgmstream/vgmstream/src/meta/xvag.c index 4236c978f..c7a365054 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/xvag.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/xvag.c @@ -26,8 +26,8 @@ typedef struct { off_t stream_offset; } xvag_header; -static int init_xvag_atrac9(STREAMFILE* sf, VGMSTREAM* vgmstream, xvag_header * xvag, off_t chunk_offset); -static layered_layout_data* build_layered_xvag(STREAMFILE* sf, xvag_header * xvag, off_t chunk_offset, off_t start_offset); +static int init_xvag_atrac9(STREAMFILE* sf, VGMSTREAM* vgmstream, xvag_header* xvag, off_t chunk_offset); +static layered_layout_data* build_layered_xvag(STREAMFILE* sf, xvag_header* xvag, off_t chunk_offset, off_t start_offset); /* XVAG - Sony's Scream Tool/Stream Creator format (God of War III, Ratchet & Clank Future, The Last of Us, Uncharted) */ VGMSTREAM* init_vgmstream_xvag(STREAMFILE* sf) { @@ -42,7 +42,7 @@ VGMSTREAM* init_vgmstream_xvag(STREAMFILE* sf) { /* checks */ /* .xvag: standard - * (extensionless): The Last Of Us (PS3) speech files */ + * (extensionless): The Last of Us (PS3) speech files */ if (!check_extensions(sf,"xvag,")) goto fail; if (!is_id32be(0x00,sf, "XVAG")) @@ -254,7 +254,7 @@ fail: } #ifdef VGM_USE_ATRAC9 -static int init_xvag_atrac9(STREAMFILE* sf, VGMSTREAM* vgmstream, xvag_header * xvag, off_t chunk_offset) { +static int init_xvag_atrac9(STREAMFILE* sf, VGMSTREAM* vgmstream, xvag_header* xvag, off_t chunk_offset) { int32_t (*read_32bit)(off_t,STREAMFILE*) = xvag->big_endian ? read_32bitBE : read_32bitLE; atrac9_config cfg = {0}; @@ -265,7 +265,7 @@ static int init_xvag_atrac9(STREAMFILE* sf, VGMSTREAM* vgmstream, xvag_header * /* 0x08: data size (layer only) */ /* 0x10: decoder delay? */ cfg.encoder_delay = read_32bit(chunk_offset+0x14,sf); - /* sometimes ATRAC9 data starts with a fake RIFF, that has total channels rather than layer channels */ + /* sometimes ATRAC9 data starts with a fake RIFF, that has total channels rather than layer channels */ vgmstream->codec_data = init_atrac9(&cfg); if (!vgmstream->codec_data) goto fail; @@ -278,7 +278,7 @@ fail: } #endif -static layered_layout_data* build_layered_xvag(STREAMFILE* sf, xvag_header * xvag, off_t chunk_offset, off_t start_offset) { +static layered_layout_data* build_layered_xvag(STREAMFILE* sf, xvag_header* xvag, off_t chunk_offset, off_t start_offset) { layered_layout_data* data = NULL; STREAMFILE* temp_sf = NULL; int32_t (*read_32bit)(off_t,STREAMFILE*) = xvag->big_endian ? read_32bitBE : read_32bitLE; @@ -309,7 +309,7 @@ static layered_layout_data* build_layered_xvag(STREAMFILE* sf, xvag_header * xva if (!init_xvag_atrac9(sf, data->layers[i], xvag, chunk_offset)) goto fail; - /* interleaves N layers for custom multichannel, may rarely use subsongs [Days Gone (PS4) multilayer test] + /* interleaves N layers for custom multichannel, may rarely use subsongs [Days Gone (PS4) multilayer test] * ex. 2 layers, 1 subsong : [L1][L2][L1][L2] * ex. 2 layers, 2 subsongs: [L1S1][L2S1][L1S2][L2S2] (assumed, could be [L1S1][L1S2][L2S1][L2S2]) */ chunk = i + xvag->subsongs * (xvag->target_subsong - 1); /* [L1S1][L2S1][L1S2][L2S2] */ diff --git a/Frameworks/vgmstream/vgmstream/src/plugins.c b/Frameworks/vgmstream/vgmstream/src/plugins.c index 2f4669484..b6206fa29 100644 --- a/Frameworks/vgmstream/vgmstream/src/plugins.c +++ b/Frameworks/vgmstream/vgmstream/src/plugins.c @@ -1,6 +1,7 @@ #include "vgmstream.h" #include "plugins.h" #include "mixing.h" +#include "util/log.h" /* ****************************************** */ @@ -546,3 +547,16 @@ void vgmstream_mixing_stereo_only(VGMSTREAM *vgmstream, int start) { /* remove channels after stereo */ mixing_push_killmix(vgmstream, start + 2); } + + +/* ****************************************** */ +/* LOG: log */ +/* ****************************************** */ + +void vgmstream_set_log_callback(int level, void* callback) { + vgm_log_set_callback(NULL, level, 0, callback); +} + +void vgmstream_set_log_stdout(int level) { + vgm_log_set_callback(NULL, level, 1, NULL); +} diff --git a/Frameworks/vgmstream/vgmstream/src/plugins.h b/Frameworks/vgmstream/vgmstream/src/plugins.h index 917c8c9b9..39688d821 100644 --- a/Frameworks/vgmstream/vgmstream/src/plugins.h +++ b/Frameworks/vgmstream/vgmstream/src/plugins.h @@ -77,6 +77,14 @@ typedef struct { /* get a simple title for plugins */ void vgmstream_get_title(char* buf, int buf_len, const char* filename, VGMSTREAM* vgmstream, vgmstream_title_t* cfg); +enum { + VGM_LOG_LEVEL_INFO = 1, + VGM_LOG_LEVEL_DEBUG = 2, + VGM_LOG_LEVEL_ALL = 100, +}; +// CB: void (*callback)(int level, const char* str) +void vgmstream_set_log_callback(int level, void* callback); +void vgmstream_set_log_stdout(int level); #if 0 diff --git a/Frameworks/vgmstream/vgmstream/src/render.c b/Frameworks/vgmstream/vgmstream/src/render.c index a3ad90a43..153101320 100644 --- a/Frameworks/vgmstream/vgmstream/src/render.c +++ b/Frameworks/vgmstream/vgmstream/src/render.c @@ -518,7 +518,7 @@ static void seek_force_loop(VGMSTREAM* vgmstream, int loop_count) { return; /* pretend decoder reached loop end so state is set to loop start */ - vgmstream->loop_count = loop_count - 1; /* seeking to first loop musy become ++ > 0 */ + vgmstream->loop_count = loop_count - 1; /* seeking to first loop must become ++ > 0 */ vgmstream->current_sample = vgmstream->loop_end_sample; vgmstream_do_loop(vgmstream); } diff --git a/Frameworks/vgmstream/vgmstream/src/streamfile.c b/Frameworks/vgmstream/vgmstream/src/streamfile.c index 424202f42..4c50853a6 100644 --- a/Frameworks/vgmstream/vgmstream/src/streamfile.c +++ b/Frameworks/vgmstream/vgmstream/src/streamfile.c @@ -1,58 +1,90 @@ -#ifndef _MSC_VER -#include -#endif #include "streamfile.h" #include "util.h" #include "vgmstream.h" +/* MSVC fixes (though mingw uses MSVCRT but not MSC_VER, maybe use AND?) */ +#if defined(__MSVCRT__) || defined(_MSC_VER) + #include + +/* + #ifndef fseeko + #define fseeko fseek + #endif + #ifndef ftello + #define ftello ftell + #endif +*/ + #define fseek_v _fseeki64 //fseek/fseeko + #define ftell_v _ftelli64 //ftell/ftello + + #ifdef fileno + #undef fileno + #endif + #define fileno _fileno + #define fdopen _fdopen + #define dup _dup + + #ifndef off64_t + #define off_t __int64 + #endif + +#elif defined(XBMC) || defined(__APPLE__) + #define fseek_v fseek + #define ftell_v ftell +#else + #define fseek_v fseeko64 //fseeko + #define ftell_v ftello64 //ftelloo +#endif + + /* a STREAMFILE that operates via standard IO using a buffer */ typedef struct { - STREAMFILE sf; /* callbacks */ + STREAMFILE vt; /* callbacks */ - FILE * infile; /* actual FILE */ + FILE* infile; /* actual FILE */ char name[PATH_LIMIT]; /* FILE filename */ - off_t offset; /* last read offset (info) */ - off_t buffer_offset; /* current buffer data start */ - uint8_t * buffer; /* data buffer */ - size_t buffersize; /* max buffer size */ - size_t validsize; /* current buffer size */ - size_t filesize; /* buffered file size */ + offv_t offset; /* last read offset (info) */ + offv_t buf_offset; /* current buffer data start */ + uint8_t* buf; /* data buffer */ + size_t buf_size; /* max buffer size */ + size_t valid_size; /* current buffer size */ + size_t file_size; /* buffered file size */ } STDIO_STREAMFILE; -static STREAMFILE* open_stdio_streamfile_buffer(const char * const filename, size_t buffersize); -static STREAMFILE* open_stdio_streamfile_buffer_by_file(FILE *infile, const char * const filename, size_t buffersize); +static STREAMFILE* open_stdio_streamfile_buffer(const char* const filename, size_t buf_size); +static STREAMFILE* open_stdio_streamfile_buffer_by_file(FILE *infile, const char* const filename, size_t buf_size); -static size_t read_stdio(STDIO_STREAMFILE *streamfile, uint8_t *dst, off_t offset, size_t length) { - size_t length_read_total = 0; +static size_t stdio_read(STDIO_STREAMFILE* sf, uint8_t* dst, offv_t offset, size_t length) { + size_t read_total = 0; - if (!streamfile->infile || !dst || length <= 0 || offset < 0) + if (!sf->infile || !dst || length <= 0 || offset < 0) return 0; - //;VGM_LOG("STDIO: read %lx + %x (buf %lx + %x)\n", offset, length, streamfile->buffer_offset, streamfile->validsize); + //;VGM_LOG("STDIO: read %lx + %x (buf %lx + %x)\n", offset, length, sf->buf_offset, sf->valid_size); /* is the part of the requested length in the buffer? */ - if (offset >= streamfile->buffer_offset && offset < streamfile->buffer_offset + streamfile->validsize) { - size_t length_to_read; - off_t offset_into_buffer = offset - streamfile->buffer_offset; + if (offset >= sf->buf_offset && offset < sf->buf_offset + sf->valid_size) { + size_t buf_limit; + int buf_into = (int)(offset - sf->buf_offset); - length_to_read = streamfile->validsize - offset_into_buffer; - if (length_to_read > length) - length_to_read = length; + buf_limit = sf->valid_size - buf_into; + if (buf_limit > length) + buf_limit = length; - //;VGM_LOG("STDIO: copy buf %lx + %x (+ %x) (buf %lx + %x)\n", offset, length_to_read, (length - length_to_read), streamfile->buffer_offset, streamfile->validsize); + //;VGM_LOG("STDIO: copy buf %lx + %x (+ %x) (buf %lx + %x)\n", offset, length_to_read, (length - length_to_read), sf->buf_offset, sf->valid_size); - memcpy(dst, streamfile->buffer + offset_into_buffer, length_to_read); - length_read_total += length_to_read; - length -= length_to_read; - offset += length_to_read; - dst += length_to_read; + memcpy(dst, sf->buf + buf_into, buf_limit); + read_total += buf_limit; + length -= buf_limit; + offset += buf_limit; + dst += buf_limit; } #ifdef VGM_DEBUG_OUTPUT - if (offset < streamfile->buffer_offset && length > 0) { - VGM_LOG("STDIO: rebuffer, requested %lx vs %lx (sf %x)\n", offset, streamfile->buffer_offset, (uint32_t)streamfile); - //streamfile->rebuffer++; + if (offset < sf->buf_offset && length > 0) { + VGM_LOG("STDIO: rebuffer, requested %lx vs %lx (sf %x)\n", offset, sf->buf_offset, (uint32_t)sf); + //sf->rebuffer++; //if (rebuffer > N) ... } #endif @@ -62,14 +94,14 @@ static size_t read_stdio(STDIO_STREAMFILE *streamfile, uint8_t *dst, off_t offse size_t length_to_read; /* ignore requests at EOF */ - if (offset >= streamfile->filesize) { - //offset = streamfile->filesize; /* seems fseek doesn't clamp offset */ - VGM_ASSERT_ONCE(offset > streamfile->filesize, "STDIO: reading over filesize 0x%x @ 0x%x + 0x%x\n", streamfile->filesize, (uint32_t)offset, length); + if (offset >= sf->file_size) { + //offset = sf->file_size; /* seems fseek doesn't clamp offset */ + VGM_ASSERT_ONCE(offset > sf->file_size, "STDIO: reading over file_size 0x%x @ 0x%x + 0x%x\n", sf->file_size, (uint32_t)offset, length); break; } /* position to new offset */ - if (fseeko(streamfile->infile,offset,SEEK_SET)) { + if (fseek_v(sf->infile, offset, SEEK_SET)) { break; /* this shouldn't happen in our code */ } @@ -78,58 +110,58 @@ static size_t read_stdio(STDIO_STREAMFILE *streamfile, uint8_t *dst, off_t offse * This bug is deterministic and seemingly appears randomly after seeking. * It results in fread returning data from the wrong area of the file. * HPS is one format that is almost always affected by this. - * May be related/same as open_stdio's bug when using dup() */ - fseek(streamfile->infile, ftell(streamfile->infile), SEEK_SET); + * May be related/same as stdio_open's fixed bug when using dup(), try disabling */ + fseek_v(sf->infile, ftell_v(sf->infile), SEEK_SET); #endif - /* fill the buffer (offset now is beyond buffer_offset) */ - streamfile->buffer_offset = offset; - streamfile->validsize = fread(streamfile->buffer, sizeof(uint8_t), streamfile->buffersize, streamfile->infile); - //;VGM_LOG("STDIO: read buf %lx + %x\n", streamfile->buffer_offset, streamfile->validsize); + /* fill the buffer (offset now is beyond buf_offset) */ + sf->buf_offset = offset; + sf->valid_size = fread(sf->buf, sizeof(uint8_t), sf->buf_size, sf->infile); + //;VGM_LOG("STDIO: read buf %lx + %x\n", sf->buf_offset, sf->valid_size); /* decide how much must be read this time */ - if (length > streamfile->buffersize) - length_to_read = streamfile->buffersize; + if (length > sf->buf_size) + length_to_read = sf->buf_size; else length_to_read = length; /* give up on partial reads (EOF) */ - if (streamfile->validsize < length_to_read) { - memcpy(dst, streamfile->buffer, streamfile->validsize); - offset += streamfile->validsize; - length_read_total += streamfile->validsize; + if (sf->valid_size < length_to_read) { + memcpy(dst, sf->buf, sf->valid_size); + offset += sf->valid_size; + read_total += sf->valid_size; break; } /* use the new buffer */ - memcpy(dst, streamfile->buffer, length_to_read); + memcpy(dst, sf->buf, length_to_read); offset += length_to_read; - length_read_total += length_to_read; + read_total += length_to_read; length -= length_to_read; dst += length_to_read; } - streamfile->offset = offset; /* last fread offset */ - return length_read_total; + sf->offset = offset; /* last fread offset */ + return read_total; } -static size_t get_size_stdio(STDIO_STREAMFILE *streamfile) { - return streamfile->filesize; +static size_t stdio_get_size(STDIO_STREAMFILE* sf) { + return sf->file_size; } -static off_t get_offset_stdio(STDIO_STREAMFILE *streamfile) { - return streamfile->offset; +static offv_t stdio_get_offset(STDIO_STREAMFILE* sf) { + return sf->offset; } -static void get_name_stdio(STDIO_STREAMFILE *streamfile, char *buffer, size_t length) { - strncpy(buffer, streamfile->name, length); - buffer[length-1]='\0'; +static void stdio_get_name(STDIO_STREAMFILE* sf, char* name, size_t name_size) { + strncpy(name, sf->name, name_size); + name[name_size - 1] = '\0'; } -static void close_stdio(STDIO_STREAMFILE *streamfile) { - if (streamfile->infile) - fclose(streamfile->infile); - free(streamfile->buffer); - free(streamfile); +static void stdio_close(STDIO_STREAMFILE* sf) { + if (sf->infile) + fclose(sf->infile); + free(sf->buf); + free(sf); } -static STREAMFILE* open_stdio(STDIO_STREAMFILE *streamfile, const char * const filename, size_t buffersize) { +static STREAMFILE* stdio_open(STDIO_STREAMFILE* sf, const char* const filename, size_t buf_size) { if (!filename) return NULL; @@ -140,12 +172,12 @@ static STREAMFILE* open_stdio(STDIO_STREAMFILE *streamfile, const char * const f * this reportedly this causes issues in Android too */ /* if same name, duplicate the file descriptor we already have open */ - if (streamfile->infile && !strcmp(streamfile->name,filename)) { + if (sf->infile && !strcmp(sf->name,filename)) { int new_fd; FILE *new_file = NULL; - if (((new_fd = dup(fileno(streamfile->infile))) >= 0) && (new_file = fdopen(new_fd, "rb"))) { - STREAMFILE *new_sf = open_stdio_streamfile_buffer_by_file(new_file, filename, buffersize); + if (((new_fd = dup(fileno(sf->infile))) >= 0) && (new_file = fdopen(new_fd, "rb"))) { + STREAMFILE* new_sf = open_stdio_streamfile_buffer_by_file(new_file, filename, buf_size); if (new_sf) return new_sf; fclose(new_file); @@ -157,61 +189,61 @@ static STREAMFILE* open_stdio(STDIO_STREAMFILE *streamfile, const char * const f } #endif // a normal open, open a new file - return open_stdio_streamfile_buffer(filename, buffersize); + return open_stdio_streamfile_buffer(filename, buf_size); } -static STREAMFILE* open_stdio_streamfile_buffer_by_file(FILE *infile, const char * const filename, size_t buffersize) { - uint8_t *buffer = NULL; - STDIO_STREAMFILE *streamfile = NULL; +static STREAMFILE* open_stdio_streamfile_buffer_by_file(FILE* infile, const char* const filename, size_t buf_size) { + uint8_t* buf = NULL; + STDIO_STREAMFILE* this_sf = NULL; - buffer = calloc(buffersize,1); - if (!buffer) goto fail; + buf = calloc(buf_size, sizeof(uint8_t)); + if (!buf) goto fail; - streamfile = calloc(1,sizeof(STDIO_STREAMFILE)); - if (!streamfile) goto fail; + this_sf = calloc(1, sizeof(STDIO_STREAMFILE)); + if (!this_sf) goto fail; - streamfile->sf.read = (void*)read_stdio; - streamfile->sf.get_size = (void*)get_size_stdio; - streamfile->sf.get_offset = (void*)get_offset_stdio; - streamfile->sf.get_name = (void*)get_name_stdio; - streamfile->sf.open = (void*)open_stdio; - streamfile->sf.close = (void*)close_stdio; + this_sf->vt.read = (void*)stdio_read; + this_sf->vt.get_size = (void*)stdio_get_size; + this_sf->vt.get_offset = (void*)stdio_get_offset; + this_sf->vt.get_name = (void*)stdio_get_name; + this_sf->vt.open = (void*)stdio_open; + this_sf->vt.close = (void*)stdio_close; - streamfile->infile = infile; - streamfile->buffersize = buffersize; - streamfile->buffer = buffer; + this_sf->infile = infile; + this_sf->buf_size = buf_size; + this_sf->buf = buf; - strncpy(streamfile->name, filename, sizeof(streamfile->name)); - streamfile->name[sizeof(streamfile->name)-1] = '\0'; + strncpy(this_sf->name, filename, sizeof(this_sf->name)); + this_sf->name[sizeof(this_sf->name)-1] = '\0'; - /* cache filesize */ + /* cache file_size */ if (infile) { - fseeko(streamfile->infile,0,SEEK_END); - streamfile->filesize = ftello(streamfile->infile); + fseek_v(this_sf->infile, 0x00, SEEK_END); + this_sf->file_size = ftell_v(this_sf->infile); + fseek_v(this_sf->infile, 0x00, SEEK_SET); } else { - streamfile->filesize = 0; /* allow virtual, non-existing files */ + this_sf->file_size = 0; /* allow virtual, non-existing files */ } /* Typically fseek(o)/ftell(o) may only handle up to ~2.14GB, signed 32b = 0x7FFFFFFF - * (happens in banks like FSB, though rarely). Can be remedied with the - * preprocessor (-D_FILE_OFFSET_BITS=64 in GCC) but it's not well tested. */ - if (streamfile->filesize == 0xFFFFFFFF) { /* -1 on error */ - VGM_LOG("STREAMFILE: ftell error\n"); + * (happens in banks like FSB, though rarely). Should work if configured properly, log otherwise. */ + if (this_sf->file_size == 0xFFFFFFFF) { /* -1 on error */ + vgm_logi("STREAMFILE: file size too big (report)\n"); goto fail; /* can be ignored but may result in strange/unexpected behaviors */ } - return &streamfile->sf; + return &this_sf->vt; fail: - free(buffer); - free(streamfile); + free(buf); + free(this_sf); return NULL; } -static STREAMFILE* open_stdio_streamfile_buffer(const char * const filename, size_t bufsize) { - FILE *infile = NULL; - STREAMFILE *streamfile = NULL; +static STREAMFILE* open_stdio_streamfile_buffer(const char* const filename, size_t bufsize) { + FILE* infile = NULL; + STREAMFILE* sf = NULL; infile = fopen(filename,"rb"); if (!infile) { @@ -220,163 +252,165 @@ static STREAMFILE* open_stdio_streamfile_buffer(const char * const filename, siz return NULL; } - streamfile = open_stdio_streamfile_buffer_by_file(infile, filename, bufsize); - if (!streamfile) { + sf = open_stdio_streamfile_buffer_by_file(infile, filename, bufsize); + if (!sf) { if (infile) fclose(infile); } - return streamfile; + return sf; } -STREAMFILE* open_stdio_streamfile(const char *filename) { +STREAMFILE* open_stdio_streamfile(const char* filename) { return open_stdio_streamfile_buffer(filename, STREAMFILE_DEFAULT_BUFFER_SIZE); } -STREAMFILE* open_stdio_streamfile_by_file(FILE *file, const char *filename) { +STREAMFILE* open_stdio_streamfile_by_file(FILE* file, const char* filename) { return open_stdio_streamfile_buffer_by_file(file, filename, STREAMFILE_DEFAULT_BUFFER_SIZE); } /* **************************************************** */ typedef struct { - STREAMFILE sf; + STREAMFILE vt; - STREAMFILE *inner_sf; - off_t offset; /* last read offset (info) */ - off_t buffer_offset; /* current buffer data start */ - uint8_t * buffer; /* data buffer */ - size_t buffersize; /* max buffer size */ - size_t validsize; /* current buffer size */ - size_t filesize; /* buffered file size */ + STREAMFILE* inner_sf; + offv_t offset; /* last read offset (info) */ + offv_t buf_offset; /* current buffer data start */ + uint8_t* buf; /* data buffer */ + size_t buf_size; /* max buffer size */ + size_t valid_size; /* current buffer size */ + size_t file_size; /* buffered file size */ } BUFFER_STREAMFILE; -static size_t buffer_read(BUFFER_STREAMFILE *streamfile, uint8_t *dst, off_t offset, size_t length) { - size_t length_read_total = 0; +static size_t buffer_read(BUFFER_STREAMFILE* sf, uint8_t* dst, offv_t offset, size_t length) { + size_t read_total = 0; if (!dst || length <= 0 || offset < 0) return 0; /* is the part of the requested length in the buffer? */ - if (offset >= streamfile->buffer_offset && offset < streamfile->buffer_offset + streamfile->validsize) { - size_t length_to_read; - off_t offset_into_buffer = offset - streamfile->buffer_offset; + if (offset >= sf->buf_offset && offset < sf->buf_offset + sf->valid_size) { + size_t buf_limit; + int buf_into = (int)(offset - sf->buf_offset); - length_to_read = streamfile->validsize - offset_into_buffer; - if (length_to_read > length) - length_to_read = length; + buf_limit = sf->valid_size - buf_into; + if (buf_limit > length) + buf_limit = length; - memcpy(dst, streamfile->buffer + offset_into_buffer, length_to_read); - length_read_total += length_to_read; - length -= length_to_read; - offset += length_to_read; - dst += length_to_read; + memcpy(dst, sf->buf + buf_into, buf_limit); + read_total += buf_limit; + length -= buf_limit; + offset += buf_limit; + dst += buf_limit; } #ifdef VGM_DEBUG_OUTPUT - if (offset < streamfile->buffer_offset) { - VGM_LOG("BUFFER: rebuffer, requested %lx vs %lx (sf %x)\n", offset, streamfile->buffer_offset, (uint32_t)streamfile); + if (offset < sf->buf_offset) { + VGM_LOG("BUFFER: rebuffer, requested %lx vs %lx (sf %x)\n", offset, sf->buf_offset, (uint32_t)sf); } #endif /* read the rest of the requested length */ while (length > 0) { - size_t length_to_read; + size_t buf_limit; /* ignore requests at EOF */ - if (offset >= streamfile->filesize) { - //offset = streamfile->filesize; /* seems fseek doesn't clamp offset */ - VGM_ASSERT_ONCE(offset > streamfile->filesize, "BUFFER: reading over filesize 0x%x @ 0x%x + 0x%x\n", streamfile->filesize, (uint32_t)offset, length); + if (offset >= sf->file_size) { + //offset = sf->file_size; /* seems fseek doesn't clamp offset */ + VGM_ASSERT_ONCE(offset > sf->file_size, "BUFFER: reading over file_size 0x%x @ 0x%x + 0x%x\n", sf->file_size, (uint32_t)offset, length); break; } - /* fill the buffer (offset now is beyond buffer_offset) */ - streamfile->buffer_offset = offset; - streamfile->validsize = streamfile->inner_sf->read(streamfile->inner_sf, streamfile->buffer, streamfile->buffer_offset, streamfile->buffersize); + /* fill the buffer (offset now is beyond buf_offset) */ + sf->buf_offset = offset; + sf->valid_size = sf->inner_sf->read(sf->inner_sf, sf->buf, sf->buf_offset, sf->buf_size); /* decide how much must be read this time */ - if (length > streamfile->buffersize) - length_to_read = streamfile->buffersize; + if (length > sf->buf_size) + buf_limit = sf->buf_size; else - length_to_read = length; + buf_limit = length; /* give up on partial reads (EOF) */ - if (streamfile->validsize < length_to_read) { - memcpy(dst, streamfile->buffer, streamfile->validsize); - offset += streamfile->validsize; - length_read_total += streamfile->validsize; + if (sf->valid_size < buf_limit) { + memcpy(dst, sf->buf, sf->valid_size); + offset += sf->valid_size; + read_total += sf->valid_size; break; } /* use the new buffer */ - memcpy(dst, streamfile->buffer, length_to_read); - offset += length_to_read; - length_read_total += length_to_read; - length -= length_to_read; - dst += length_to_read; + memcpy(dst, sf->buf, buf_limit); + offset += buf_limit; + read_total += buf_limit; + length -= buf_limit; + dst += buf_limit; } - streamfile->offset = offset; /* last fread offset */ - return length_read_total; + sf->offset = offset; /* last fread offset */ + return read_total; } -static size_t buffer_get_size(BUFFER_STREAMFILE *streamfile) { - return streamfile->filesize; /* cache */ +static size_t buffer_get_size(BUFFER_STREAMFILE* sf) { + return sf->file_size; /* cache */ } -static size_t buffer_get_offset(BUFFER_STREAMFILE *streamfile) { - return streamfile->offset; /* cache */ +static offv_t buffer_get_offset(BUFFER_STREAMFILE* sf) { + return sf->offset; /* cache */ } -static void buffer_get_name(BUFFER_STREAMFILE *streamfile, char *buffer, size_t length) { - streamfile->inner_sf->get_name(streamfile->inner_sf, buffer, length); /* default */ +static void buffer_get_name(BUFFER_STREAMFILE* sf, char* name, size_t name_size) { + sf->inner_sf->get_name(sf->inner_sf, name, name_size); /* default */ } -static STREAMFILE *buffer_open(BUFFER_STREAMFILE *streamfile, const char * const filename, size_t buffersize) { - STREAMFILE *new_inner_sf = streamfile->inner_sf->open(streamfile->inner_sf,filename,buffersize); - return open_buffer_streamfile(new_inner_sf, buffersize); /* original buffer size is preferable? */ +static STREAMFILE* buffer_open(BUFFER_STREAMFILE* sf, const char* const filename, size_t buf_size) { + STREAMFILE* new_inner_sf = sf->inner_sf->open(sf->inner_sf,filename,buf_size); + return open_buffer_streamfile(new_inner_sf, buf_size); /* original buffer size is preferable? */ } -static void buffer_close(BUFFER_STREAMFILE *streamfile) { - streamfile->inner_sf->close(streamfile->inner_sf); - free(streamfile->buffer); - free(streamfile); +static void buffer_close(BUFFER_STREAMFILE* sf) { + sf->inner_sf->close(sf->inner_sf); + free(sf->buf); + free(sf); } -STREAMFILE* open_buffer_streamfile(STREAMFILE *streamfile, size_t buffer_size) { - BUFFER_STREAMFILE *this_sf = NULL; +STREAMFILE* open_buffer_streamfile(STREAMFILE* sf, size_t buf_size) { + uint8_t* buf = NULL; + BUFFER_STREAMFILE* this_sf = NULL; - if (!streamfile) goto fail; + if (!sf) goto fail; + + if (buf_size == 0) + buf_size = STREAMFILE_DEFAULT_BUFFER_SIZE; + + buf = calloc(buf_size, sizeof(uint8_t)); + if (!buf) goto fail; this_sf = calloc(1, sizeof(BUFFER_STREAMFILE)); if (!this_sf) goto fail; - this_sf->buffersize = buffer_size; - if (this_sf->buffersize == 0) - this_sf->buffersize = STREAMFILE_DEFAULT_BUFFER_SIZE; - - this_sf->buffer = calloc(this_sf->buffersize,1); - if (!this_sf->buffer) goto fail; - /* set callbacks and internals */ - this_sf->sf.read = (void*)buffer_read; - this_sf->sf.get_size = (void*)buffer_get_size; - this_sf->sf.get_offset = (void*)buffer_get_offset; - this_sf->sf.get_name = (void*)buffer_get_name; - this_sf->sf.open = (void*)buffer_open; - this_sf->sf.close = (void*)buffer_close; - this_sf->sf.stream_index = streamfile->stream_index; + this_sf->vt.read = (void*)buffer_read; + this_sf->vt.get_size = (void*)buffer_get_size; + this_sf->vt.get_offset = (void*)buffer_get_offset; + this_sf->vt.get_name = (void*)buffer_get_name; + this_sf->vt.open = (void*)buffer_open; + this_sf->vt.close = (void*)buffer_close; + this_sf->vt.stream_index = sf->stream_index; - this_sf->inner_sf = streamfile; + this_sf->inner_sf = sf; + this_sf->buf_size = buf_size; + this_sf->buf = buf; - this_sf->filesize = streamfile->get_size(streamfile); + this_sf->file_size = sf->get_size(sf); - return &this_sf->sf; + return &this_sf->vt; fail: - if (this_sf) free(this_sf->buffer); + if (this_sf) free(this_sf->buf); free(this_sf); return NULL; } -STREAMFILE* open_buffer_streamfile_f(STREAMFILE *streamfile, size_t buffer_size) { - STREAMFILE *new_sf = open_buffer_streamfile(streamfile, buffer_size); +STREAMFILE* open_buffer_streamfile_f(STREAMFILE* sf, size_t buffer_size) { + STREAMFILE* new_sf = open_buffer_streamfile(sf, buffer_size); if (!new_sf) - close_streamfile(streamfile); + close_streamfile(sf); return new_sf; } @@ -387,201 +421,201 @@ STREAMFILE* open_buffer_streamfile_f(STREAMFILE *streamfile, size_t buffer_size) //todo use safe string ops, this ain't easy typedef struct { - STREAMFILE sf; + STREAMFILE vt; - STREAMFILE *inner_sf; + STREAMFILE* inner_sf; } WRAP_STREAMFILE; -static size_t wrap_read(WRAP_STREAMFILE *streamfile, uint8_t *dst, off_t offset, size_t length) { - return streamfile->inner_sf->read(streamfile->inner_sf, dst, offset, length); /* default */ +static size_t wrap_read(WRAP_STREAMFILE* sf, uint8_t* dst, offv_t offset, size_t length) { + return sf->inner_sf->read(sf->inner_sf, dst, offset, length); /* default */ } -static size_t wrap_get_size(WRAP_STREAMFILE *streamfile) { - return streamfile->inner_sf->get_size(streamfile->inner_sf); /* default */ +static size_t wrap_get_size(WRAP_STREAMFILE* sf) { + return sf->inner_sf->get_size(sf->inner_sf); /* default */ } -static size_t wrap_get_offset(WRAP_STREAMFILE *streamfile) { - return streamfile->inner_sf->get_offset(streamfile->inner_sf); /* default */ +static offv_t wrap_get_offset(WRAP_STREAMFILE* sf) { + return sf->inner_sf->get_offset(sf->inner_sf); /* default */ } -static void wrap_get_name(WRAP_STREAMFILE *streamfile, char *buffer, size_t length) { - streamfile->inner_sf->get_name(streamfile->inner_sf, buffer, length); /* default */ +static void wrap_get_name(WRAP_STREAMFILE* sf, char* name, size_t name_len) { + sf->inner_sf->get_name(sf->inner_sf, name, name_len); /* default */ } -static void wrap_open(WRAP_STREAMFILE *streamfile, const char * const filename, size_t buffersize) { - streamfile->inner_sf->open(streamfile->inner_sf, filename, buffersize); /* default (don't wrap) */ +static void wrap_open(WRAP_STREAMFILE* sf, const char* const filename, size_t buf_size) { + sf->inner_sf->open(sf->inner_sf, filename, buf_size); /* default (don't wrap) */ } -static void wrap_close(WRAP_STREAMFILE *streamfile) { - //streamfile->inner_sf->close(streamfile->inner_sf); /* don't close */ - free(streamfile); +static void wrap_close(WRAP_STREAMFILE* sf) { + //sf->inner_sf->close(sf->inner_sf); /* don't close */ + free(sf); } -STREAMFILE* open_wrap_streamfile(STREAMFILE *streamfile) { - WRAP_STREAMFILE *this_sf = NULL; +STREAMFILE* open_wrap_streamfile(STREAMFILE* sf) { + WRAP_STREAMFILE* this_sf = NULL; - if (!streamfile) return NULL; + if (!sf) return NULL; - this_sf = calloc(1,sizeof(WRAP_STREAMFILE)); + this_sf = calloc(1, sizeof(WRAP_STREAMFILE)); if (!this_sf) return NULL; /* set callbacks and internals */ - this_sf->sf.read = (void*)wrap_read; - this_sf->sf.get_size = (void*)wrap_get_size; - this_sf->sf.get_offset = (void*)wrap_get_offset; - this_sf->sf.get_name = (void*)wrap_get_name; - this_sf->sf.open = (void*)wrap_open; - this_sf->sf.close = (void*)wrap_close; - this_sf->sf.stream_index = streamfile->stream_index; + this_sf->vt.read = (void*)wrap_read; + this_sf->vt.get_size = (void*)wrap_get_size; + this_sf->vt.get_offset = (void*)wrap_get_offset; + this_sf->vt.get_name = (void*)wrap_get_name; + this_sf->vt.open = (void*)wrap_open; + this_sf->vt.close = (void*)wrap_close; + this_sf->vt.stream_index = sf->stream_index; - this_sf->inner_sf = streamfile; + this_sf->inner_sf = sf; - return &this_sf->sf; + return &this_sf->vt; } -STREAMFILE* open_wrap_streamfile_f(STREAMFILE* streamfile) { - STREAMFILE* new_sf = open_wrap_streamfile(streamfile); +STREAMFILE* open_wrap_streamfile_f(STREAMFILE* sf) { + STREAMFILE* new_sf = open_wrap_streamfile(sf); if (!new_sf) - close_streamfile(streamfile); + close_streamfile(sf); return new_sf; } /* **************************************************** */ typedef struct { - STREAMFILE sf; + STREAMFILE vt; STREAMFILE* inner_sf; - off_t start; + offv_t start; size_t size; } CLAMP_STREAMFILE; -static size_t clamp_read(CLAMP_STREAMFILE* streamfile, uint8_t* dst, off_t offset, size_t length) { - off_t inner_offset = streamfile->start + offset; +static size_t clamp_read(CLAMP_STREAMFILE* sf, uint8_t* dst, offv_t offset, size_t length) { + offv_t inner_offset = sf->start + offset; size_t clamp_length = length; - if (offset + length > streamfile->size) { - if (offset >= streamfile->size) + if (offset + length > sf->size) { + if (offset >= sf->size) clamp_length = 0; else - clamp_length = streamfile->size - offset; + clamp_length = sf->size - offset; } - return streamfile->inner_sf->read(streamfile->inner_sf, dst, inner_offset, clamp_length); + return sf->inner_sf->read(sf->inner_sf, dst, inner_offset, clamp_length); } -static size_t clamp_get_size(CLAMP_STREAMFILE* streamfile) { - return streamfile->size; +static size_t clamp_get_size(CLAMP_STREAMFILE* sf) { + return sf->size; } -static off_t clamp_get_offset(CLAMP_STREAMFILE* streamfile) { - return streamfile->inner_sf->get_offset(streamfile->inner_sf) - streamfile->start; +static offv_t clamp_get_offset(CLAMP_STREAMFILE* sf) { + return sf->inner_sf->get_offset(sf->inner_sf) - sf->start; } -static void clamp_get_name(CLAMP_STREAMFILE* streamfile, char* buffer, size_t length) { - streamfile->inner_sf->get_name(streamfile->inner_sf, buffer, length); /* default */ +static void clamp_get_name(CLAMP_STREAMFILE* sf, char* name, size_t name_len) { + sf->inner_sf->get_name(sf->inner_sf, name, name_len); /* default */ } -static STREAMFILE* clamp_open(CLAMP_STREAMFILE* streamfile, const char* const filename, size_t buffersize) { +static STREAMFILE* clamp_open(CLAMP_STREAMFILE* sf, const char* const filename, size_t buf_size) { char original_filename[PATH_LIMIT]; STREAMFILE* new_inner_sf = NULL; - new_inner_sf = streamfile->inner_sf->open(streamfile->inner_sf,filename,buffersize); - streamfile->inner_sf->get_name(streamfile->inner_sf, original_filename, PATH_LIMIT); + new_inner_sf = sf->inner_sf->open(sf->inner_sf,filename,buf_size); + sf->inner_sf->get_name(sf->inner_sf, original_filename, PATH_LIMIT); /* detect re-opening the file */ if (strcmp(filename, original_filename) == 0) { - return open_clamp_streamfile(new_inner_sf, streamfile->start, streamfile->size); /* clamp again */ + return open_clamp_streamfile(new_inner_sf, sf->start, sf->size); /* clamp again */ } else { return new_inner_sf; } } -static void clamp_close(CLAMP_STREAMFILE* streamfile) { - streamfile->inner_sf->close(streamfile->inner_sf); - free(streamfile); +static void clamp_close(CLAMP_STREAMFILE* sf) { + sf->inner_sf->close(sf->inner_sf); + free(sf); } -STREAMFILE* open_clamp_streamfile(STREAMFILE* streamfile, off_t start, size_t size) { +STREAMFILE* open_clamp_streamfile(STREAMFILE* sf, offv_t start, size_t size) { CLAMP_STREAMFILE* this_sf = NULL; - if (!streamfile || size == 0) return NULL; - if (start + size > get_streamfile_size(streamfile)) return NULL; + if (!sf || size == 0) return NULL; + if (start + size > get_streamfile_size(sf)) return NULL; - this_sf = calloc(1,sizeof(CLAMP_STREAMFILE)); + this_sf = calloc(1, sizeof(CLAMP_STREAMFILE)); if (!this_sf) return NULL; /* set callbacks and internals */ - this_sf->sf.read = (void*)clamp_read; - this_sf->sf.get_size = (void*)clamp_get_size; - this_sf->sf.get_offset = (void*)clamp_get_offset; - this_sf->sf.get_name = (void*)clamp_get_name; - this_sf->sf.open = (void*)clamp_open; - this_sf->sf.close = (void*)clamp_close; - this_sf->sf.stream_index = streamfile->stream_index; + this_sf->vt.read = (void*)clamp_read; + this_sf->vt.get_size = (void*)clamp_get_size; + this_sf->vt.get_offset = (void*)clamp_get_offset; + this_sf->vt.get_name = (void*)clamp_get_name; + this_sf->vt.open = (void*)clamp_open; + this_sf->vt.close = (void*)clamp_close; + this_sf->vt.stream_index = sf->stream_index; - this_sf->inner_sf = streamfile; + this_sf->inner_sf = sf; this_sf->start = start; this_sf->size = size; - return &this_sf->sf; + return &this_sf->vt; } -STREAMFILE* open_clamp_streamfile_f(STREAMFILE* streamfile, off_t start, size_t size) { - STREAMFILE* new_sf = open_clamp_streamfile(streamfile, start, size); +STREAMFILE* open_clamp_streamfile_f(STREAMFILE* sf, offv_t start, size_t size) { + STREAMFILE* new_sf = open_clamp_streamfile(sf, start, size); if (!new_sf) - close_streamfile(streamfile); + close_streamfile(sf); return new_sf; } /* **************************************************** */ typedef struct { - STREAMFILE sf; + STREAMFILE vt; - STREAMFILE *inner_sf; + STREAMFILE* inner_sf; void* data; /* state for custom reads, malloc'ed + copied on open (to re-open streamfiles cleanly) */ size_t data_size; - size_t (*read_callback)(STREAMFILE *, uint8_t *, off_t, size_t, void*); /* custom read to modify data before copying into buffer */ - size_t (*size_callback)(STREAMFILE *, void*); /* size when custom reads make data smaller/bigger than underlying streamfile */ + size_t (*read_callback)(STREAMFILE*, uint8_t*, offv_t, size_t, void*); /* custom read to modify data before copying into buffer */ + size_t (*size_callback)(STREAMFILE*, void*); /* size when custom reads make data smaller/bigger than underlying streamfile */ int (*init_callback)(STREAMFILE*, void*); /* init the data struct members somehow, return >= 0 if ok */ void (*close_callback)(STREAMFILE*, void*); /* close the data struct members somehow */ } IO_STREAMFILE; -static size_t io_read(IO_STREAMFILE *streamfile, uint8_t *dst, off_t offset, size_t length) { - return streamfile->read_callback(streamfile->inner_sf, dst, offset, length, streamfile->data); +static size_t io_read(IO_STREAMFILE* sf, uint8_t* dst, offv_t offset, size_t length) { + return sf->read_callback(sf->inner_sf, dst, offset, length, sf->data); } -static size_t io_get_size(IO_STREAMFILE *streamfile) { - if (streamfile->size_callback) - return streamfile->size_callback(streamfile->inner_sf, streamfile->data); +static size_t io_get_size(IO_STREAMFILE* sf) { + if (sf->size_callback) + return sf->size_callback(sf->inner_sf, sf->data); else - return streamfile->inner_sf->get_size(streamfile->inner_sf); /* default */ + return sf->inner_sf->get_size(sf->inner_sf); /* default */ } -static off_t io_get_offset(IO_STREAMFILE *streamfile) { - return streamfile->inner_sf->get_offset(streamfile->inner_sf); /* default */ +static offv_t io_get_offset(IO_STREAMFILE* sf) { + return sf->inner_sf->get_offset(sf->inner_sf); /* default */ } -static void io_get_name(IO_STREAMFILE *streamfile, char *buffer, size_t length) { - streamfile->inner_sf->get_name(streamfile->inner_sf, buffer, length); /* default */ +static void io_get_name(IO_STREAMFILE* sf, char* name, size_t name_len) { + sf->inner_sf->get_name(sf->inner_sf, name, name_len); /* default */ } -static STREAMFILE* io_open(IO_STREAMFILE *streamfile, const char * const filename, size_t buffersize) { - STREAMFILE *new_inner_sf = streamfile->inner_sf->open(streamfile->inner_sf,filename,buffersize); - return open_io_streamfile_ex(new_inner_sf, streamfile->data, streamfile->data_size, streamfile->read_callback, streamfile->size_callback, streamfile->init_callback, streamfile->close_callback); +static STREAMFILE* io_open(IO_STREAMFILE* sf, const char* const filename, size_t buf_size) { + STREAMFILE* new_inner_sf = sf->inner_sf->open(sf->inner_sf,filename,buf_size); + return open_io_streamfile_ex(new_inner_sf, sf->data, sf->data_size, sf->read_callback, sf->size_callback, sf->init_callback, sf->close_callback); } -static void io_close(IO_STREAMFILE *streamfile) { - if (streamfile->close_callback) - streamfile->close_callback(streamfile->inner_sf, streamfile->data); - streamfile->inner_sf->close(streamfile->inner_sf); - free(streamfile->data); - free(streamfile); +static void io_close(IO_STREAMFILE* sf) { + if (sf->close_callback) + sf->close_callback(sf->inner_sf, sf->data); + sf->inner_sf->close(sf->inner_sf); + free(sf->data); + free(sf); } -STREAMFILE* open_io_streamfile_ex(STREAMFILE *streamfile, void *data, size_t data_size, void *read_callback, void *size_callback, void* init_callback, void* close_callback) { - IO_STREAMFILE *this_sf = NULL; +STREAMFILE* open_io_streamfile_ex(STREAMFILE* sf, void* data, size_t data_size, void* read_callback, void* size_callback, void* init_callback, void* close_callback) { + IO_STREAMFILE* this_sf = NULL; - if (!streamfile) goto fail; + if (!sf) goto fail; if ((data && !data_size) || (!data && data_size)) goto fail; - this_sf = calloc(1,sizeof(IO_STREAMFILE)); + this_sf = calloc(1, sizeof(IO_STREAMFILE)); if (!this_sf) goto fail; /* set callbacks and internals */ - this_sf->sf.read = (void*)io_read; - this_sf->sf.get_size = (void*)io_get_size; - this_sf->sf.get_offset = (void*)io_get_offset; - this_sf->sf.get_name = (void*)io_get_name; - this_sf->sf.open = (void*)io_open; - this_sf->sf.close = (void*)io_close; - this_sf->sf.stream_index = streamfile->stream_index; + this_sf->vt.read = (void*)io_read; + this_sf->vt.get_size = (void*)io_get_size; + this_sf->vt.get_offset = (void*)io_get_offset; + this_sf->vt.get_name = (void*)io_get_name; + this_sf->vt.open = (void*)io_open; + this_sf->vt.close = (void*)io_close; + this_sf->vt.stream_index = sf->stream_index; - this_sf->inner_sf = streamfile; + this_sf->inner_sf = sf; if (data) { this_sf->data = malloc(data_size); if (!this_sf->data) goto fail; @@ -598,7 +632,7 @@ STREAMFILE* open_io_streamfile_ex(STREAMFILE *streamfile, void *data, size_t dat if (ok < 0) goto fail; } - return &this_sf->sf; + return &this_sf->vt; fail: if (this_sf) free(this_sf->data); @@ -606,89 +640,89 @@ fail: return NULL; } -STREAMFILE* open_io_streamfile_ex_f(STREAMFILE *streamfile, void *data, size_t data_size, void *read_callback, void *size_callback, void* init_callback, void* close_callback) { - STREAMFILE *new_sf = open_io_streamfile_ex(streamfile, data, data_size, read_callback, size_callback, init_callback, close_callback); +STREAMFILE* open_io_streamfile_ex_f(STREAMFILE* sf, void* data, size_t data_size, void* read_callback, void* size_callback, void* init_callback, void* close_callback) { + STREAMFILE* new_sf = open_io_streamfile_ex(sf, data, data_size, read_callback, size_callback, init_callback, close_callback); if (!new_sf) - close_streamfile(streamfile); + close_streamfile(sf); return new_sf; } -STREAMFILE* open_io_streamfile(STREAMFILE *streamfile, void *data, size_t data_size, void *read_callback, void *size_callback) { - return open_io_streamfile_ex(streamfile, data, data_size, read_callback, size_callback, NULL, NULL); +STREAMFILE* open_io_streamfile(STREAMFILE* sf, void* data, size_t data_size, void* read_callback, void* size_callback) { + return open_io_streamfile_ex(sf, data, data_size, read_callback, size_callback, NULL, NULL); } -STREAMFILE* open_io_streamfile_f(STREAMFILE *streamfile, void *data, size_t data_size, void *read_callback, void *size_callback) { - return open_io_streamfile_ex_f(streamfile, data, data_size, read_callback, size_callback, NULL, NULL); +STREAMFILE* open_io_streamfile_f(STREAMFILE* sf, void* data, size_t data_size, void* read_callback, void* size_callback) { + return open_io_streamfile_ex_f(sf, data, data_size, read_callback, size_callback, NULL, NULL); } /* **************************************************** */ typedef struct { - STREAMFILE sf; + STREAMFILE vt; - STREAMFILE *inner_sf; + STREAMFILE* inner_sf; char fakename[PATH_LIMIT]; } FAKENAME_STREAMFILE; -static size_t fakename_read(FAKENAME_STREAMFILE *streamfile, uint8_t *dst, off_t offset, size_t length) { - return streamfile->inner_sf->read(streamfile->inner_sf, dst, offset, length); /* default */ +static size_t fakename_read(FAKENAME_STREAMFILE* sf, uint8_t* dst, offv_t offset, size_t length) { + return sf->inner_sf->read(sf->inner_sf, dst, offset, length); /* default */ } -static size_t fakename_get_size(FAKENAME_STREAMFILE *streamfile) { - return streamfile->inner_sf->get_size(streamfile->inner_sf); /* default */ +static size_t fakename_get_size(FAKENAME_STREAMFILE* sf) { + return sf->inner_sf->get_size(sf->inner_sf); /* default */ } -static size_t fakename_get_offset(FAKENAME_STREAMFILE *streamfile) { - return streamfile->inner_sf->get_offset(streamfile->inner_sf); /* default */ +static offv_t fakename_get_offset(FAKENAME_STREAMFILE* sf) { + return sf->inner_sf->get_offset(sf->inner_sf); /* default */ } -static void fakename_get_name(FAKENAME_STREAMFILE *streamfile, char *buffer, size_t length) { - strncpy(buffer,streamfile->fakename,length); - buffer[length-1]='\0'; +static void fakename_get_name(FAKENAME_STREAMFILE* sf, char* name, size_t name_size) { + strncpy(name,sf->fakename, name_size); + name[name_size - 1] = '\0'; } -static STREAMFILE* fakename_open(FAKENAME_STREAMFILE *streamfile, const char * const filename, size_t buffersize) { +static STREAMFILE* fakename_open(FAKENAME_STREAMFILE* sf, const char* const filename, size_t buf_size) { /* detect re-opening the file */ - if (strcmp(filename, streamfile->fakename) == 0) { - STREAMFILE *new_inner_sf; + if (strcmp(filename, sf->fakename) == 0) { + STREAMFILE* new_inner_sf; char original_filename[PATH_LIMIT]; - streamfile->inner_sf->get_name(streamfile->inner_sf, original_filename, PATH_LIMIT); - new_inner_sf = streamfile->inner_sf->open(streamfile->inner_sf, original_filename, buffersize); - return open_fakename_streamfile(new_inner_sf, streamfile->fakename, NULL); + sf->inner_sf->get_name(sf->inner_sf, original_filename, PATH_LIMIT); + new_inner_sf = sf->inner_sf->open(sf->inner_sf, original_filename, buf_size); + return open_fakename_streamfile(new_inner_sf, sf->fakename, NULL); } else { - return streamfile->inner_sf->open(streamfile->inner_sf, filename, buffersize); + return sf->inner_sf->open(sf->inner_sf, filename, buf_size); } } -static void fakename_close(FAKENAME_STREAMFILE *streamfile) { - streamfile->inner_sf->close(streamfile->inner_sf); - free(streamfile); +static void fakename_close(FAKENAME_STREAMFILE* sf) { + sf->inner_sf->close(sf->inner_sf); + free(sf); } -STREAMFILE* open_fakename_streamfile(STREAMFILE *streamfile, const char *fakename, const char *fakeext) { - FAKENAME_STREAMFILE *this_sf = NULL; +STREAMFILE* open_fakename_streamfile(STREAMFILE* sf, const char* fakename, const char* fakeext) { + FAKENAME_STREAMFILE* this_sf = NULL; - if (!streamfile || (!fakename && !fakeext)) return NULL; + if (!sf || (!fakename && !fakeext)) return NULL; - this_sf = calloc(1,sizeof(FAKENAME_STREAMFILE)); + this_sf = calloc(1, sizeof(FAKENAME_STREAMFILE)); if (!this_sf) return NULL; /* set callbacks and internals */ - this_sf->sf.read = (void*)fakename_read; - this_sf->sf.get_size = (void*)fakename_get_size; - this_sf->sf.get_offset = (void*)fakename_get_offset; - this_sf->sf.get_name = (void*)fakename_get_name; - this_sf->sf.open = (void*)fakename_open; - this_sf->sf.close = (void*)fakename_close; - this_sf->sf.stream_index = streamfile->stream_index; + this_sf->vt.read = (void*)fakename_read; + this_sf->vt.get_size = (void*)fakename_get_size; + this_sf->vt.get_offset = (void*)fakename_get_offset; + this_sf->vt.get_name = (void*)fakename_get_name; + this_sf->vt.open = (void*)fakename_open; + this_sf->vt.close = (void*)fakename_close; + this_sf->vt.stream_index = sf->stream_index; - this_sf->inner_sf = streamfile; + this_sf->inner_sf = sf; /* copy passed name or retain current, and swap extension if expected */ if (fakename) { strcpy(this_sf->fakename,fakename); } else { - streamfile->get_name(streamfile, this_sf->fakename, PATH_LIMIT); + sf->get_name(sf, this_sf->fakename, PATH_LIMIT); } if (fakeext) { - char* ext = strrchr(this_sf->fakename,'.'); + char* ext = strrchr(this_sf->fakename, '.'); if (ext != NULL) { ext[1] = '\0'; /* truncate past dot */ } else { @@ -697,40 +731,40 @@ STREAMFILE* open_fakename_streamfile(STREAMFILE *streamfile, const char *fakenam strcat(this_sf->fakename, fakeext); } - return &this_sf->sf; + return &this_sf->vt; } -STREAMFILE* open_fakename_streamfile_f(STREAMFILE *streamfile, const char *fakename, const char *fakeext) { - STREAMFILE *new_sf = open_fakename_streamfile(streamfile, fakename, fakeext); +STREAMFILE* open_fakename_streamfile_f(STREAMFILE* sf, const char* fakename, const char* fakeext) { + STREAMFILE* new_sf = open_fakename_streamfile(sf, fakename, fakeext); if (!new_sf) - close_streamfile(streamfile); + close_streamfile(sf); return new_sf; } /* **************************************************** */ typedef struct { - STREAMFILE sf; + STREAMFILE vt; - STREAMFILE **inner_sfs; + STREAMFILE** inner_sfs; size_t inner_sfs_size; size_t *sizes; - off_t size; - off_t offset; + offv_t size; + offv_t offset; } MULTIFILE_STREAMFILE; -static size_t multifile_read(MULTIFILE_STREAMFILE *streamfile, uint8_t *dst, off_t offset, size_t length) { +static size_t multifile_read(MULTIFILE_STREAMFILE* sf, uint8_t* dst, offv_t offset, size_t length) { int i, segment = 0; - off_t segment_offset = 0; + offv_t segment_offset = 0; size_t done = 0; - if (offset > streamfile->size) { - streamfile->offset = streamfile->size; + if (offset > sf->size) { + sf->offset = sf->size; return 0; } /* map external offset to multifile offset */ - for (i = 0; i < streamfile->inner_sfs_size; i++) { - size_t segment_size = streamfile->sizes[i]; + for (i = 0; i < sf->inner_sfs_size; i++) { + size_t segment_size = sf->sizes[i]; /* check if offset falls in this segment */ if (offset >= segment_offset && offset < segment_offset + segment_size) { segment = i; @@ -743,110 +777,110 @@ static size_t multifile_read(MULTIFILE_STREAMFILE *streamfile, uint8_t *dst, off /* reads can span multiple segments */ while(done < length) { - if (segment >= streamfile->inner_sfs_size) /* over last segment, not fully done */ + if (segment >= sf->inner_sfs_size) /* over last segment, not fully done */ break; /* reads over segment size are ok, will return smaller value and continue next segment */ - done += streamfile->inner_sfs[segment]->read(streamfile->inner_sfs[segment], dst + done, segment_offset, length - done); + done += sf->inner_sfs[segment]->read(sf->inner_sfs[segment], dst + done, segment_offset, length - done); segment++; segment_offset = 0; } - streamfile->offset = offset + done; + sf->offset = offset + done; return done; } -static size_t multifile_get_size(MULTIFILE_STREAMFILE *streamfile) { - return streamfile->size; +static size_t multifile_get_size(MULTIFILE_STREAMFILE* sf) { + return sf->size; } -static size_t multifile_get_offset(MULTIFILE_STREAMFILE * streamfile) { - return streamfile->offset; +static offv_t multifile_get_offset(MULTIFILE_STREAMFILE* sf) { + return sf->offset; } -static void multifile_get_name(MULTIFILE_STREAMFILE *streamfile, char *buffer, size_t length) { - streamfile->inner_sfs[0]->get_name(streamfile->inner_sfs[0], buffer, length); +static void multifile_get_name(MULTIFILE_STREAMFILE* sf, char* name, size_t name_size) { + sf->inner_sfs[0]->get_name(sf->inner_sfs[0], name, name_size); } -static STREAMFILE* multifile_open(MULTIFILE_STREAMFILE *streamfile, const char * const filename, size_t buffersize) { +static STREAMFILE* multifile_open(MULTIFILE_STREAMFILE* sf, const char* const filename, size_t buf_size) { char original_filename[PATH_LIMIT]; - STREAMFILE *new_sf = NULL; - STREAMFILE **new_inner_sfs = NULL; + STREAMFILE* new_sf = NULL; + STREAMFILE** new_inner_sfs = NULL; int i; - streamfile->inner_sfs[0]->get_name(streamfile->inner_sfs[0], original_filename, PATH_LIMIT); + sf->inner_sfs[0]->get_name(sf->inner_sfs[0], original_filename, PATH_LIMIT); /* detect re-opening the file */ if (strcmp(filename, original_filename) == 0) { /* same multifile */ - new_inner_sfs = calloc(streamfile->inner_sfs_size, sizeof(STREAMFILE*)); + new_inner_sfs = calloc(sf->inner_sfs_size, sizeof(STREAMFILE*)); if (!new_inner_sfs) goto fail; - for (i = 0; i < streamfile->inner_sfs_size; i++) { - streamfile->inner_sfs[i]->get_name(streamfile->inner_sfs[i], original_filename, PATH_LIMIT); - new_inner_sfs[i] = streamfile->inner_sfs[i]->open(streamfile->inner_sfs[i], original_filename, buffersize); + for (i = 0; i < sf->inner_sfs_size; i++) { + sf->inner_sfs[i]->get_name(sf->inner_sfs[i], original_filename, PATH_LIMIT); + new_inner_sfs[i] = sf->inner_sfs[i]->open(sf->inner_sfs[i], original_filename, buf_size); if (!new_inner_sfs[i]) goto fail; } - new_sf = open_multifile_streamfile(new_inner_sfs, streamfile->inner_sfs_size); + new_sf = open_multifile_streamfile(new_inner_sfs, sf->inner_sfs_size); if (!new_sf) goto fail; free(new_inner_sfs); return new_sf; } else { - return streamfile->inner_sfs[0]->open(streamfile->inner_sfs[0], filename, buffersize); /* regular file */ + return sf->inner_sfs[0]->open(sf->inner_sfs[0], filename, buf_size); /* regular file */ } fail: if (new_inner_sfs) { - for (i = 0; i < streamfile->inner_sfs_size; i++) + for (i = 0; i < sf->inner_sfs_size; i++) close_streamfile(new_inner_sfs[i]); } free(new_inner_sfs); return NULL; } -static void multifile_close(MULTIFILE_STREAMFILE *streamfile) { +static void multifile_close(MULTIFILE_STREAMFILE* sf) { int i; - for (i = 0; i < streamfile->inner_sfs_size; i++) { - for (i = 0; i < streamfile->inner_sfs_size; i++) { - close_streamfile(streamfile->inner_sfs[i]); + for (i = 0; i < sf->inner_sfs_size; i++) { + for (i = 0; i < sf->inner_sfs_size; i++) { + close_streamfile(sf->inner_sfs[i]); } } - free(streamfile->inner_sfs); - free(streamfile->sizes); - free(streamfile); + free(sf->inner_sfs); + free(sf->sizes); + free(sf); } -STREAMFILE* open_multifile_streamfile(STREAMFILE **streamfiles, size_t streamfiles_size) { - MULTIFILE_STREAMFILE *this_sf = NULL; +STREAMFILE* open_multifile_streamfile(STREAMFILE** sfs, size_t sfs_size) { + MULTIFILE_STREAMFILE* this_sf = NULL; int i; - if (!streamfiles || !streamfiles_size) return NULL; + if (!sfs || !sfs_size) return NULL; - for (i = 0; i < streamfiles_size; i++) { - if (!streamfiles[i]) return NULL; + for (i = 0; i < sfs_size; i++) { + if (!sfs[i]) return NULL; } - this_sf = calloc(1,sizeof(MULTIFILE_STREAMFILE)); + this_sf = calloc(1, sizeof(MULTIFILE_STREAMFILE)); if (!this_sf) goto fail; /* set callbacks and internals */ - this_sf->sf.read = (void*)multifile_read; - this_sf->sf.get_size = (void*)multifile_get_size; - this_sf->sf.get_offset = (void*)multifile_get_offset; - this_sf->sf.get_name = (void*)multifile_get_name; - this_sf->sf.open = (void*)multifile_open; - this_sf->sf.close = (void*)multifile_close; - this_sf->sf.stream_index = streamfiles[0]->stream_index; + this_sf->vt.read = (void*)multifile_read; + this_sf->vt.get_size = (void*)multifile_get_size; + this_sf->vt.get_offset = (void*)multifile_get_offset; + this_sf->vt.get_name = (void*)multifile_get_name; + this_sf->vt.open = (void*)multifile_open; + this_sf->vt.close = (void*)multifile_close; + this_sf->vt.stream_index = sfs[0]->stream_index; - this_sf->inner_sfs_size = streamfiles_size; - this_sf->inner_sfs = calloc(streamfiles_size, sizeof(STREAMFILE*)); + this_sf->inner_sfs_size = sfs_size; + this_sf->inner_sfs = calloc(sfs_size, sizeof(STREAMFILE*)); if (!this_sf->inner_sfs) goto fail; - this_sf->sizes = calloc(streamfiles_size, sizeof(size_t)); + this_sf->sizes = calloc(sfs_size, sizeof(size_t)); if (!this_sf->sizes) goto fail; for (i = 0; i < this_sf->inner_sfs_size; i++) { - this_sf->inner_sfs[i] = streamfiles[i]; - this_sf->sizes[i] = streamfiles[i]->get_size(streamfiles[i]); + this_sf->inner_sfs[i] = sfs[i]; + this_sf->sizes[i] = sfs[i]->get_size(sfs[i]); this_sf->size += this_sf->sizes[i]; } - return &this_sf->sf; + return &this_sf->vt; fail: if (this_sf) { @@ -856,12 +890,12 @@ fail: free(this_sf); return NULL; } -STREAMFILE* open_multifile_streamfile_f(STREAMFILE **streamfiles, size_t streamfiles_size) { - STREAMFILE *new_sf = open_multifile_streamfile(streamfiles, streamfiles_size); +STREAMFILE* open_multifile_streamfile_f(STREAMFILE** sfs, size_t sfs_size) { + STREAMFILE* new_sf = open_multifile_streamfile(sfs, sfs_size); if (!new_sf) { int i; - for (i = 0; i < streamfiles_size; i++) { - close_streamfile(streamfiles[i]); + for (i = 0; i < sfs_size; i++) { + close_streamfile(sfs[i]); } } return new_sf; @@ -925,7 +959,7 @@ STREAMFILE* open_streamfile_by_filename(STREAMFILE* sf, const char* filename) { name = partname + 2; /* ignore './' */ } else if (partname[0] == '.' && partname[1] == '.' && partname[2] == DIR_SEPARATOR) { /* '../name' */ - char *pathprev; + char* pathprev; path[0] = '\0'; /* remove last separator so next call works */ pathprev = strrchr(fullname,DIR_SEPARATOR); @@ -1241,7 +1275,7 @@ int check_extensions(STREAMFILE* sf, const char* cmp_exts) { const char* ststr_res = NULL; size_t ext_len, cmp_len; - sf->get_name(sf,filename,sizeof(filename)); + sf->get_name(sf, filename, sizeof(filename)); ext = filename_extension(filename); ext_len = strlen(ext); @@ -1410,15 +1444,15 @@ void get_streamfile_ext(STREAMFILE* sf, char* buffer, size_t size) { /* debug util, mainly for custom IO testing */ void dump_streamfile(STREAMFILE* sf, int num) { #ifdef VGM_DEBUG_OUTPUT - off_t offset = 0; + offv_t offset = 0; FILE* f = NULL; if (num >= 0) { char filename[PATH_LIMIT]; char dumpname[PATH_LIMIT]; - get_streamfile_filename(sf, filename, PATH_LIMIT); - snprintf(dumpname,PATH_LIMIT, "%s_%02i.dump", filename, num); + get_streamfile_filename(sf, filename, sizeof(filename)); + snprintf(dumpname, sizeof(dumpname), "%s_%02i.dump", filename, num); f = fopen(dumpname,"wb"); if (!f) return; @@ -1426,20 +1460,20 @@ void dump_streamfile(STREAMFILE* sf, int num) { VGM_LOG("dump streamfile: size %x\n", get_streamfile_size(sf)); while (offset < get_streamfile_size(sf)) { - uint8_t buffer[0x8000]; - size_t read; + uint8_t buf[0x8000]; + size_t bytes; - read = read_streamfile(buffer,offset,0x8000,sf); - if(!read) { + bytes = read_streamfile(buf, offset, sizeof(buf), sf); + if(!bytes) { VGM_LOG("dump streamfile: can't read at %lx\n", offset); break; } if (f) - fwrite(buffer,sizeof(uint8_t),read, f); + fwrite(buf, sizeof(uint8_t), bytes, f); else - VGM_LOGB(buffer,read,0); - offset += read; + VGM_LOGB(buf, bytes, 0); + offset += bytes; } if (f) { diff --git a/Frameworks/vgmstream/vgmstream/src/streamfile.h b/Frameworks/vgmstream/vgmstream/src/streamfile.h index 1ab12705f..6c5525550 100644 --- a/Frameworks/vgmstream/vgmstream/src/streamfile.h +++ b/Frameworks/vgmstream/vgmstream/src/streamfile.h @@ -19,40 +19,34 @@ /* MSVC fixes (though mingw uses MSVCRT but not MSC_VER, maybe use AND?) */ #if defined(__MSVCRT__) || defined(_MSC_VER) - #include + #include - #ifndef fseeko - #define fseeko fseek - #endif - #ifndef ftello - #define ftello ftell - #endif - - #define dup _dup - - #ifdef fileno - #undef fileno - #endif - #define fileno _fileno - #define fdopen _fdopen - -// #ifndef off64_t -// #define off_t __int64 -// #endif -#endif - -#if defined(XBMC) -#define fseeko fseek + #ifndef off64_t + #define off_t __int64 + #endif #endif #ifndef DIR_SEPARATOR -#if defined (_WIN32) || defined (WIN32) -#define DIR_SEPARATOR '\\' -#else -#define DIR_SEPARATOR '/' -#endif + #if defined (_WIN32) || defined (WIN32) + #define DIR_SEPARATOR '\\' + #else + #define DIR_SEPARATOR '/' + #endif #endif +/* 64-bit offset is needed for banks that hit +2.5GB (like .fsb or .ktsl2stbin). + * Leave as typedef to toggle since it's theoretically slower when compiled as 32-bit. + * ATM it's only used in choice places until more performance tests are done. + * uint32_t could be an option but needs to test when/how neg offsets are used. + * + * On POSIX 32-bit off_t can become off64_t by passing -D_FILE_OFFSET_BITS=64, + * but not on MSVC as it doesn't have proper POSIX support, so a custom type is needed. + * fseeks/tells also need to be adjusted for 64-bit support. + */ +typedef int64_t offv_t; //off64_t +//typedef int64_t sizev_t; // size_t int64_t off64_t + + /* Streamfiles normally use an internal buffer to increase performance, configurable * but usually of this size. Lower increases the number of freads/system calls (slower). * However some formats need to jump around causing more buffer trashing than usual, @@ -65,17 +59,26 @@ * to do file operations, as plugins may need to provide their own callbacks. * Reads from arbitrary offsets, meaning internally may need fseek equivalents during reads. */ typedef struct _STREAMFILE { - size_t (*read)(struct _STREAMFILE*, uint8_t* dst, off_t offset, size_t length); - size_t (*get_size)(struct _STREAMFILE*); - off_t (*get_offset)(struct _STREAMFILE*); //todo: DO NOT USE, NOT RESET PROPERLY (remove?) - /* for dual-file support */ - void (*get_name)(struct _STREAMFILE*, char* name, size_t length); - struct _STREAMFILE* (*open)(struct _STREAMFILE*, const char* const filename, size_t buffersize); + /* read 'length' data at 'offset' to 'dst' */ + size_t (*read)(struct _STREAMFILE* sf, uint8_t* dst, offv_t offset, size_t length); + + /* get max offset */ + size_t (*get_size)(struct _STREAMFILE* sf); + + //todo: DO NOT USE, NOT RESET PROPERLY (remove?) + offv_t (*get_offset)(struct _STREAMFILE*); + + /* copy current filename to name buf */ + void (*get_name)(struct _STREAMFILE* sf, char* name, size_t name_size); + + /* open another streamfile from filename */ + struct _STREAMFILE* (*open)(struct _STREAMFILE* sf, const char* const filename, size_t buffer_size); + + /* free current STREAMFILE */ void (*close)(struct _STREAMFILE*); - - /* Substream selection for files with subsongs. Manually used in metas if supported. - * Not ideal here, but it's the simplest way to pass to all init_vgmstream_x functions. */ + /* Substream selection for formats with subsongs. + * Not ideal here, but it was the simplest way to pass to all init_vgmstream_x functions. */ int stream_index; /* 0=default/auto (first), 1=first, N=Nth */ } STREAMFILE; @@ -105,8 +108,8 @@ STREAMFILE* open_wrap_streamfile_f(STREAMFILE* sf); /* Opens a STREAMFILE that clamps reads to a section of a larger streamfile. * Can be used with subfiles inside a bigger file (to fool metas, or to simplify custom IO). */ -STREAMFILE* open_clamp_streamfile(STREAMFILE* sf, off_t start, size_t size); -STREAMFILE* open_clamp_streamfile_f(STREAMFILE* sf, off_t start, size_t size); +STREAMFILE* open_clamp_streamfile(STREAMFILE* sf, offv_t start, size_t size); +STREAMFILE* open_clamp_streamfile_f(STREAMFILE* sf, offv_t start, size_t size); /* Opens a STREAMFILE that uses custom IO for streamfile reads. * Can be used to modify data on the fly (ex. decryption), or even transform it from a format to another. @@ -156,8 +159,8 @@ static inline void close_streamfile(STREAMFILE* sf) { } /* read from a file, returns number of bytes read */ -static inline size_t read_streamfile(uint8_t *dst, off_t offset, size_t length, STREAMFILE* sf) { - return sf->read(sf, dst, offset,length); +static inline size_t read_streamfile(uint8_t* dst, offv_t offset, size_t length, STREAMFILE* sf) { + return sf->read(sf, dst, offset, length); } /* return file size */ diff --git a/Frameworks/vgmstream/vgmstream/src/util.h b/Frameworks/vgmstream/vgmstream/src/util.h index 72eeb0066..7df0a9f7a 100644 --- a/Frameworks/vgmstream/vgmstream/src/util.h +++ b/Frameworks/vgmstream/vgmstream/src/util.h @@ -136,49 +136,4 @@ void swap_samples_le(sample_t *buf, int count); void concatn(int length, char * dst, const char * src); - -/* Simple stdout logging for debugging and regression testing purposes. - * Needs C99 variadic macros, uses do..while to force ";" as statement */ -#ifdef VGM_DEBUG_OUTPUT - -/* equivalent to printf when condition is true */ -#define VGM_ASSERT(condition, ...) \ - do { if (condition) {printf(__VA_ARGS__);} } while (0) -#define VGM_ASSERT_ONCE(condition, ...) \ - do { static int written; if (!written) { if (condition) {printf(__VA_ARGS__); written = 1;} } } while (0) -/* equivalent to printf */ -#define VGM_LOG(...) \ - do { printf(__VA_ARGS__); } while (0) -#define VGM_LOG_ONCE(...) \ - do { static int written; if (!written) { printf(__VA_ARGS__); written = 1; } } while (0) -/* prints file/line/func */ -#define VGM_LOGF() \ - do { printf("%s:%i '%s'\n", __FILE__, __LINE__, __func__); } while (0) -/* prints to a file */ -#define VGM_LOGT(txt, ...) \ - do { FILE *fl = fopen(txt,"a+"); if(fl){fprintf(fl,__VA_ARGS__); fflush(fl);} fclose(fl); } while(0) -/* prints a buffer/array */ -#define VGM_LOGB(buf, buf_size, bytes_per_line) \ - do { \ - int i; \ - for (i=0; i < buf_size; i++) { \ - printf("%02x",buf[i]); \ - if (bytes_per_line && (i+1) % bytes_per_line == 0) printf("\n"); \ - } \ - printf("\n"); \ - } while (0) - -#else/*VGM_DEBUG_OUTPUT*/ - -#define VGM_ASSERT(condition, ...) /* nothing */ -#define VGM_ASSERT_ONCE(condition, ...) /* nothing */ -#define VGM_LOG(...) /* nothing */ -#define VGM_LOG_ONCE(...) /* nothing */ -#define VGM_LOGF() /* nothing */ -#define VGM_LOGT() /* nothing */ -#define VGM_LOGB(buf, buf_size, bytes_per_line) /* nothing */ - - -#endif/*VGM_DEBUG_OUTPUT*/ - #endif diff --git a/Frameworks/vgmstream/vgmstream/src/util/chunks.c b/Frameworks/vgmstream/vgmstream/src/util/chunks.c new file mode 100644 index 000000000..214865864 --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/util/chunks.c @@ -0,0 +1,35 @@ +#include "chunks.h" +//#include "log.h" + + +int next_chunk(chunk_t* chunk, STREAMFILE* sf) { + uint32_t (*read_u32type)(off_t,STREAMFILE*) = !chunk->le_type ? read_u32be : read_u32le; + uint32_t (*read_u32size)(off_t,STREAMFILE*) = chunk->be_size ? read_u32be : read_u32le; + + if (chunk->max == 0) + chunk->max = get_streamfile_size(sf); + + if (chunk->current >= chunk->max) + return 0; + /* can be used to signal "stop" */ + if (chunk->current < 0) + return 0; + + chunk->type = read_u32type(chunk->current + 0x00,sf); + chunk->size = read_u32size(chunk->current + 0x04,sf); + + chunk->offset = chunk->current + 0x04 + 0x04; + chunk->current += chunk->full_size ? chunk->size : 0x08 + chunk->size; + //;VGM_LOG("CHUNK: %x, %x, %x\n", dc.offset, chunk->type, chunk->size); + + /* read past data */ + if (chunk->type == 0xFFFFFFFF || chunk->size == 0xFFFFFFFF) + return 0; + + /* empty chunk with 0 size, seen in some formats (XVAG uses it as end marker, Wwise doesn't) */ + if (chunk->type == 0 || chunk->size == 0) + return 0; + + /* more chunks remain */ + return 1; +} diff --git a/Frameworks/vgmstream/vgmstream/src/util/chunks.h b/Frameworks/vgmstream/vgmstream/src/util/chunks.h new file mode 100644 index 000000000..0df77cc53 --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/util/chunks.h @@ -0,0 +1,27 @@ +#ifndef _UTIL_CHUNKS_H +#define _UTIL_CHUNKS_H + +#include "../streamfile.h" + +typedef struct { + uint32_t type; /* chunk id/fourcc */ + uint32_t size; /* chunk size */ + uint32_t offset; /* chunk offset (after type/size) */ + off_t current; /* start position, or next chunk after size (set to -1 to break) */ + off_t max; /* max offset, or filesize if not set */ + + int le_type; /* read type as LE instead of more common BE */ + int be_size; /* read type as BE instead of more common LE */ + int full_size; /* chunk size includes type+size */ +} chunk_t; + +int next_chunk(chunk_t* chunk, STREAMFILE* sf); + +#if 0 +enum { + CHUNK_RIFF = 0x52494646, /* "RIFF" */ + CHUNK_LIST = 0x4C495354, /* "LIST" */ +}; +#endif + +#endif diff --git a/Frameworks/vgmstream/vgmstream/src/util/log.c b/Frameworks/vgmstream/vgmstream/src/util/log.c new file mode 100644 index 000000000..cd02c2da7 --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/util/log.c @@ -0,0 +1,90 @@ +#include +#include +#include +#include + +/* log context; should probably make a unique instance and pass to metas/decoders/etc, but for the time being use global */ +//extern ...* log; + +typedef struct { + int level; + void (*callback)(int level, const char* str); +} logger_t; + +logger_t log_impl = {0}; +//void* log = &log_impl; + +enum { + LOG_LEVEL_INFO = 1, + LOG_LEVEL_DEBUG = 2, + LOG_LEVEL_ALL = 100, +}; + +static void vgm_log_callback_printf(int level, const char* str) { + printf("%s", str); +} + +void vgm_log_set_callback(void* ctx_p, int level, int type, void* callback) { + logger_t* ctx = ctx_p; + if (!ctx) ctx = &log_impl; + + ctx->level = level; + + switch(type) { + case 0: + ctx->callback = callback; + break; + case 1: + ctx->callback = vgm_log_callback_printf; + break; + default: + break; + } +} + +static void log_internal(void* ctx_p, int level, const char* fmt, va_list args) { + char line[255]; + int out; + logger_t* ctx = ctx_p; + if (!ctx) ctx = &log_impl; + + if (!ctx->callback) + return; + + if (level > ctx->level) + return; + + out = vsnprintf(line, sizeof(line), fmt, args); + if (out < 0 || out > sizeof(line)) + strcpy(line, "(ignored log)"); //to-do something better, meh + ctx->callback(level, line); +} + +void vgm_logd(const char* fmt, ...) { + va_list args; + + va_start(args, fmt); + log_internal(NULL, LOG_LEVEL_DEBUG, fmt, args); + va_end(args); +} + +void vgm_logi(const char* fmt, ...) { + va_list args; + + va_start(args, fmt); + log_internal(NULL, LOG_LEVEL_INFO, fmt, args); + va_end(args); +} + +void vgm_asserti(int condition, const char* fmt, ...) { + if (!condition) + return; + + { + va_list args; + + va_start(args, fmt); + log_internal(NULL, LOG_LEVEL_INFO, fmt, args); + va_end(args); + } +} diff --git a/Frameworks/vgmstream/vgmstream/src/util/log.h b/Frameworks/vgmstream/vgmstream/src/util/log.h new file mode 100644 index 000000000..6bcbfa970 --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/util/log.h @@ -0,0 +1,78 @@ +#ifndef _UTIL_LOG_H +#define _UTIL_LOG_H + +/* Dumb logger utils (tuned for simplicity). Notes: + * - must set callback/defaults to print anything + * - mainly used to print info for users, like format detected but wrong size + * (don't clutter by logging code that happens most of the time, since log may be shared with other plugins) + * - callbacks receive formed string for simplicity (to be adjusted) + * - DO NOT put logs in tight loops (like decoders), slow fn calls and clutter + * (metas are usually fine but also consider cluttering) + * - as compiler must support variable args, needs to pass VGM_LOG_OUTPUT flag to enable + * - debug logs are removed unless VGM_DEBUG_OUTPUT is passed to compiler args + * (passing either of them works) + * - callback should be thread-safe (no internal checks and only one log ATM) + * - still WIP, some stuff not working ATM or may change + */ + +// void (*callback)(int level, const char* str); +void vgm_log_set_callback(void* ctx_p, int level, int type, void* callback); + +#if defined(VGM_LOG_OUTPUT) || defined(VGM_DEBUG_OUTPUT) + void vgm_logi(/*void* ctx,*/ const char* fmt, ...); + void vgm_asserti(/*void* ctx,*/ int condition, const char* fmt, ...); + //void vgm_logi_once(/*void* ctx, int* once_flag, */ const char* fmt, ...); +#else + #define vgm_logi(...) /* nothing */ + #define vgm_asserti(...) /* nothing */ +#endif + +#ifdef VGM_DEBUG_OUTPUT + void vgm_logd(/*void* ctx,*/ const char* fmt, ...); + #define VGM_LOG(...) do { vgm_logd(__VA_ARGS__); } while (0) + #define VGM_ASSERT(condition, ...) do { if (condition) {vgm_logd(__VA_ARGS__);} } while (0) +#else + #define vgm_logd(...) /* nothing */ + #define VGM_LOG(...) /* nothing */ + #define VGM_ASSERT(condition, ...) /* nothing */ +#endif + + +/* original stdout logging for debugging and regression testing purposes, may be removed later. + * Needs C99 variadic macros, uses do..while to force ";" as statement */ +#ifdef VGM_DEBUG_OUTPUT + + #define VGM_LOG_ONCE(...) \ + do { static int written; if (!written) { printf(__VA_ARGS__); written = 1; } } while (0) + + #define VGM_ASSERT_ONCE(condition, ...) \ + do { static int written; if (!written) { if (condition) {printf(__VA_ARGS__); written = 1;} } } while (0) + + /* prints to a file */ + #define VGM_LOGT(txt, ...) \ + do { FILE *fl = fopen(txt,"a+"); if(fl){fprintf(fl,__VA_ARGS__); fflush(fl);} fclose(fl); } while(0) + + /* prints a buffer/array */ + #define VGM_LOGB(buf, buf_size, bytes_per_line) \ + do { \ + int i; \ + for (i=0; i < buf_size; i++) { \ + printf("%02x",buf[i]); \ + if (bytes_per_line && (i+1) % bytes_per_line == 0) printf("\n"); \ + } \ + printf("\n"); \ + } while (0) + +#else /* VGM_DEBUG_OUTPUT */ + + #define VGM_LOG_ONCE(...) /* nothing */ + + #define VGM_ASSERT_ONCE(condition, ...) /* nothing */ + + #define VGM_LOGT() /* nothing */ + + #define VGM_LOGB(buf, buf_size, bytes_per_line) /* nothing */ + +#endif /*VGM_DEBUG_OUTPUT*/ + +#endif diff --git a/Frameworks/vgmstream/vgmstream/src/vgmstream.c b/Frameworks/vgmstream/vgmstream/src/vgmstream.c index fa85e4d60..aef983f34 100644 --- a/Frameworks/vgmstream/vgmstream/src/vgmstream.c +++ b/Frameworks/vgmstream/vgmstream/src/vgmstream.c @@ -24,7 +24,6 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = { init_vgmstream_bfwav, init_vgmstream_bfstm, init_vgmstream_mca, - init_vgmstream_btsnd, init_vgmstream_nds_strm, init_vgmstream_agsc, init_vgmstream_ngc_adpdtk, @@ -533,6 +532,7 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = { /* lowest priority metas (should go after all metas, and TXTH should go before raw formats) */ init_vgmstream_txth, /* proper parsers should supersede TXTH, once added */ init_vgmstream_encrypted, /* encrypted stuff */ + init_vgmstream_btsnd, /* semi-headerless */ init_vgmstream_raw_int, /* .int raw PCM */ init_vgmstream_ps_headerless, /* tries to detect a bunch of PS-ADPCM formats */ init_vgmstream_raw_snds, /* .snds raw SNDS IMA (*after* ps_headerless) */ @@ -911,6 +911,8 @@ void describe_vgmstream(VGMSTREAM* vgmstream, char* desc, int length) { char temp[TEMPSIZE]; double time_mm, time_ss; + desc[0] = '\0'; + if (!vgmstream) { snprintf(temp,TEMPSIZE, "NULL VGMSTREAM"); concatn(length,desc,temp); diff --git a/Frameworks/vgmstream/vgmstream/src/vgmstream.h b/Frameworks/vgmstream/vgmstream/src/vgmstream.h index 1ed7e0a29..8a9e81c40 100644 --- a/Frameworks/vgmstream/vgmstream/src/vgmstream.h +++ b/Frameworks/vgmstream/vgmstream/src/vgmstream.h @@ -18,6 +18,12 @@ enum { #include "streamfile.h" +#ifdef BUILD_VGMSTREAM +#include "util/log.h" +#else +#include +#endif + /* Due mostly to licensing issues, Vorbis, MPEG, G.722.1, etc decoding is done by external libraries. * Libs are disabled by default, defined on compile-time for builds that support it */ //#define VGM_USE_VORBIS diff --git a/Plugins/vgmstream/vgmstream/VGMContainer.m b/Plugins/vgmstream/vgmstream/VGMContainer.m index 894ce6b9c..6f3b31e57 100755 --- a/Plugins/vgmstream/vgmstream/VGMContainer.m +++ b/Plugins/vgmstream/vgmstream/VGMContainer.m @@ -14,6 +14,11 @@ @implementation VGMContainer ++ (void)initialize +{ + register_log_callback(); +} + + (NSArray *)fileTypes { return [VGMDecoder fileTypes]; diff --git a/Plugins/vgmstream/vgmstream/VGMDecoder.m b/Plugins/vgmstream/vgmstream/VGMDecoder.m index 46946280e..8d27e2b05 100644 --- a/Plugins/vgmstream/vgmstream/VGMDecoder.m +++ b/Plugins/vgmstream/vgmstream/VGMDecoder.m @@ -205,6 +205,11 @@ @implementation VGMDecoder ++ (void)initialize +{ + register_log_callback(); +} + - (BOOL)open:(id)s { int track_num = [[[s url] fragment] intValue]; diff --git a/Plugins/vgmstream/vgmstream/VGMInterface.h b/Plugins/vgmstream/vgmstream/VGMInterface.h index a95546fc5..d8d1593e0 100644 --- a/Plugins/vgmstream/vgmstream/VGMInterface.h +++ b/Plugins/vgmstream/vgmstream/VGMInterface.h @@ -12,10 +12,12 @@ typedef struct _COGSTREAMFILE { STREAMFILE sf; void *file; - off_t offset; + offv_t offset; char name[PATH_LIMIT]; } COGSTREAMFILE; STREAMFILE *cogsf_create_from_url(NSURL * url); VGMSTREAM *init_vgmstream_from_cogfile(const char *path, int subsong); + +void register_log_callback(); diff --git a/Plugins/vgmstream/vgmstream/VGMInterface.m b/Plugins/vgmstream/vgmstream/VGMInterface.m index 3d930dc5d..160574e61 100644 --- a/Plugins/vgmstream/vgmstream/VGMInterface.m +++ b/Plugins/vgmstream/vgmstream/VGMInterface.m @@ -10,7 +10,17 @@ #import "Plugin.h" -static void cogsf_seek(COGSTREAMFILE *this, off_t offset) { +#import "Logging.h" + +static void log_callback(int level, const char *str) { + ALog(@"%@", str); +} + +void register_log_callback() { + vgmstream_set_log_callback(VGM_LOG_LEVEL_ALL, &log_callback); +} + +static void cogsf_seek(COGSTREAMFILE *this, offv_t offset) { if (!this) return; NSObject* _file = (__bridge NSObject *)(this->file); id __unsafe_unretained file = (id) _file; @@ -20,18 +30,18 @@ static void cogsf_seek(COGSTREAMFILE *this, off_t offset) { this->offset = [file tell]; } -static off_t cogsf_get_size(COGSTREAMFILE *this) { +static offv_t cogsf_get_size(COGSTREAMFILE *this) { if (!this) return 0; NSObject* _file = (__bridge NSObject *)(this->file); id __unsafe_unretained file = (id) _file; - off_t offset = [file tell]; + offv_t offset = [file tell]; [file seek:0 whence:SEEK_END]; - off_t size = [file tell]; + offv_t size = [file tell]; [file seek:offset whence:SEEK_SET]; return size; } -static off_t cogsf_get_offset(COGSTREAMFILE *this) { +static offv_t cogsf_get_offset(COGSTREAMFILE *this) { if (!this) return 0; return this->offset; } @@ -47,7 +57,7 @@ static void cogsf_get_name(COGSTREAMFILE *this, char *buffer, size_t length) { buffer[length-1]='\0'; } -static size_t cogsf_read(COGSTREAMFILE *this, uint8_t *dest, off_t offset, size_t length) { +static size_t cogsf_read(COGSTREAMFILE *this, uint8_t *dest, offv_t offset, size_t length) { if (!this) return 0; NSObject* _file = (__bridge NSObject *)(this->file); id __unsafe_unretained file = (id) _file;