From af6a1e7469cc9b0d070ccf9b364edb7bc4b38ec3 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 12 Sep 2021 20:02:21 +0200 Subject: [PATCH 1/9] utils: fix get_id32 with non-ascii chars --- src/util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util.h b/src/util.h index e4560245..e19a0f82 100644 --- a/src/util.h +++ b/src/util.h @@ -140,7 +140,7 @@ static inline int clamp16(int32_t val) { /* transforms a string to uint32 (for comparison), but if this is static + all goes well * compiler should pre-calculate and use uint32 directly */ static inline /*const*/ uint32_t get_id32be(const char* s) { - return (uint32_t)(s[0] << 24) | (s[1] << 16) | (s[2] << 8) | (s[3] << 0); + return (uint32_t)((uint8_t)s[0] << 24) | ((uint8_t)s[1] << 16) | ((uint8_t)s[2] << 8) | ((uint8_t)s[3] << 0); } //static inline /*const*/ uint32_t get_id32le(const char* s) { From 89ed00a98026347893fafd55a99f2e0df9453a4f Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 12 Sep 2021 20:02:52 +0200 Subject: [PATCH 2/9] Fix some .p3d [Spider-Man 4 beta (X360)] --- src/meta/p3d.c | 182 ++++++++++++++++++++++++++----------------------- 1 file changed, 98 insertions(+), 84 deletions(-) diff --git a/src/meta/p3d.c b/src/meta/p3d.c index 6e1b7799..2e3895f9 100644 --- a/src/meta/p3d.c +++ b/src/meta/p3d.c @@ -1,139 +1,152 @@ #include "meta.h" #include "../coding/coding.h" -/* P3D - from Radical's Prototype 1/2 (PC/PS3/X360) */ -VGMSTREAM * init_vgmstream_p3d(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - off_t start_offset, parse_offset, name_offset = 0; +/* P3D - from Radical's Prototype 1/2 (PC/PS3/X360), Spider-Man 4 Beta (X360) */ +VGMSTREAM* init_vgmstream_p3d(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; + off_t start_offset, offset, name_offset = 0; size_t header_size, file_size, data_size; - int loop_flag = 0, channel_count, sample_rate, codec; - int i, name_count, text_len, block_size = 0, block_count = 0, num_samples; - int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL; + uint32_t xma2_offset = 0, xma2_size = 0; + int loop_flag, channels, sample_rate, codec; + int i, name_count, text_len, block_size = 0, num_samples; + uint32_t (*read_u32)(off_t,STREAMFILE*) = NULL; /* checks */ - if (!check_extensions(streamFile,"p3d")) + if (!is_id32be(0x00,sf, "P3D\xFF") && /* LE: PC */ + !is_id32le(0x00,sf, "P3D\xFF")) /* BE: PS3, X360 */ goto fail; - if (read_32bitBE(0x0,streamFile) != 0x503344FF && /* "P3D"\FF (LE: PC) */ - read_32bitBE(0x0,streamFile) != 0xFF443350) /* \FF"D3P" (BE: PS3, X360) */ + if (!check_extensions(sf,"p3d")) goto fail; - read_32bit = read_32bitBE(0x0,streamFile) == 0xFF443350 ? read_32bitBE : read_32bitLE; - file_size = get_streamfile_size(streamFile); + read_u32 = guess_endianness32bit(0x04,sf) ? read_u32be : read_u32le; + file_size = get_streamfile_size(sf); /* base header */ - header_size = read_32bit(0x4,streamFile); - if (0x0C != header_size) goto fail; - if (read_32bit(0x08,streamFile) != file_size) goto fail; - if (read_32bit(0x0C,streamFile) != 0xFE000000) goto fail; /* fixed */ - if (read_32bit(0x10,streamFile) + header_size != file_size) goto fail; - if (read_32bit(0x14,streamFile) + header_size != file_size) goto fail; /* body size again */ - if (read_32bit(0x18,streamFile) != 0x0000000A) goto fail; /* fixed */ + header_size = read_u32(0x04,sf); + if (header_size != 0x0C) goto fail; + if (read_u32(0x08,sf) != file_size) goto fail; + if (read_u32(0x0C,sf) != 0xFE000000) goto fail; /* fixed */ + if (read_u32(0x10,sf) + header_size != file_size) goto fail; + if (read_u32(0x14,sf) + header_size != file_size) goto fail; /* body size again */ + if (read_u32(0x18,sf) != 0x0000000A) goto fail; /* fixed */ /* header text */ - parse_offset = 0x1C; - text_len = read_32bit(parse_offset,streamFile); - if (9 != text_len) goto fail; - parse_offset += 4; + offset = 0x1C; + text_len = read_u32(offset,sf); + if (text_len != 9) goto fail; + offset += 0x04; /* check the type as P3D is just a generic container used in Radical's games */ - if (read_32bitBE(parse_offset+0x00,streamFile) != 0x41756469 || - read_32bitBE(parse_offset+0x04,streamFile) != 0x6F46696C || - read_16bitBE(parse_offset+0x08,streamFile) != 0x6500) goto fail; /* "AudioFile\0" */ - parse_offset += text_len + 1; + if (!is_id64be(offset+0x00,sf, "AudioFil") || read_u16be(offset+0x08,sf) != 0x6500) /* "AudioFile\0" */ + goto fail; + offset += text_len + 0x01; /* file names: always 2 (repeated); but if it's 3 there is an extra string later */ - name_count = read_32bit(parse_offset,streamFile); + name_count = read_u32(offset,sf); if (name_count != 2 && name_count != 3) goto fail; /* 2: Prototype1, 3: Prototype2 */ - parse_offset += 4; + offset += 0x04; /* skip names */ for (i = 0; i < 2; i++) { if (!name_offset) - name_offset = parse_offset + 4; - text_len = read_32bit(parse_offset,streamFile) + 1; /* null-terminated */ - parse_offset += 4 + text_len; + name_offset = offset + 0x04; + text_len = read_u32(offset,sf) + 1; /* null-terminated */ + offset += 0x04 + text_len; } /* info count? */ - if (0x01 != read_32bit(parse_offset,streamFile)) goto fail; - parse_offset += 4; + if (0x01 != read_u32(offset,sf)) goto fail; + offset += 0x04; /* next string can be used as a codec id */ - text_len = read_32bit(parse_offset,streamFile); - codec = read_32bitBE(parse_offset+4,streamFile); - parse_offset += 4 + text_len + 1; + text_len = read_u32(offset,sf); + codec = read_u32be(offset+0x04,sf); + offset += 0x04 + text_len + 0x01; /* extra "Music" string in Prototype 2 */ if (name_count == 3) { - text_len = read_32bit(parse_offset,streamFile) + 1; /* null-terminated */ - parse_offset += 4 + text_len; + text_len = read_u32(offset,sf) + 1; /* null-terminated */ + offset += 0x04 + text_len; } + loop_flag = 0; /* sub-header per codec */ switch(codec) { case 0x72616470: /* "radp" (PC) */ - if (read_32bitBE(parse_offset,streamFile) != 0x52414450) goto fail; /* "RADP" */ - parse_offset += 0x04; - channel_count = read_32bit(parse_offset+0x00,streamFile); - sample_rate = read_32bit(parse_offset+0x04,streamFile); + if (!is_id32be(offset,sf, "RADP")) + goto fail; + offset += 0x04; + + channels = read_u32(offset+0x00,sf); + sample_rate = read_u32(offset+0x04,sf); /* 0x08: ? (0x0F) */ - data_size = read_32bit(parse_offset+0x0c,streamFile); - block_size = 0x14; - num_samples = data_size / block_size / channel_count * 32; - start_offset = parse_offset+0x10; + data_size = read_u32(offset+0x0c,sf); + block_size = 0x14; + + num_samples = data_size / block_size / channels * 32; + start_offset = offset + 0x10; break; case 0x6D703300: /* "mp3\0" (PS3) */ - if ((read_32bitBE(parse_offset,streamFile) & 0xFFFFFF00) != 0x6D703300) goto fail; /* "mp3" */ - parse_offset += 0x03; + if ((read_u32be(offset,sf) & 0xFFFFFF00) != get_id32be("mp3\0")) + goto fail; + offset += 0x03; + /* all fields LE even though the prev parts were BE */ - sample_rate = read_32bitLE(parse_offset+0x00,streamFile); + sample_rate = read_s32le(offset+0x00,sf); /* 0x04: mp3 sample rate (ex. @0x00 is 47999 and @0x04 is 48000) */ - num_samples = read_32bitLE(parse_offset+0x08,streamFile); - data_size = read_32bitLE(parse_offset+0x0c,streamFile); - channel_count = read_32bitLE(parse_offset+0x10,streamFile); - block_size = read_32bitLE(parse_offset+0x14,streamFile); - num_samples = num_samples / channel_count; /* total samples */ - start_offset = parse_offset+0x18; + num_samples = read_s32le(offset+0x08,sf); + data_size = read_u32le(offset+0x0c,sf); + channels = read_s32le(offset+0x10,sf); + block_size = read_u32le(offset+0x14,sf); + + num_samples = num_samples / channels; /* total samples */ + start_offset = offset + 0x18; break; - case 0x786D6100: /* "xma\0" (X360) */ - if (read_32bitBE(parse_offset,streamFile) != 0x584D4132) goto fail; /* "XMA2" */ - parse_offset += 0x04; - /* 0x00: subheader size? (0x2c), 0x04: seek table size */ - data_size = read_32bitBE(parse_offset+0x08,streamFile); - /* 0x0c: ?, 0x10: ?, 0x14/18: 0x0 */ - sample_rate = read_32bitBE(parse_offset+0x1c,streamFile); - /* 0x20: XMA decoder params, 0x24: abr */ - block_size = read_32bitBE(parse_offset+0x28,streamFile); - num_samples = read_32bitBE(parse_offset+0x2c,streamFile); - /* 0x30: original file's samples */ - block_count = read_32bitBE(parse_offset+0x34,streamFile); - channel_count = read_8bit(parse_offset+0x38,streamFile); - /* 0x39: channel related? (stream config? channel layout?) */ - start_offset = parse_offset + 0x3c + read_32bitBE(parse_offset+0x04,streamFile); + case 0x786D6100: { /* "xma\0" (X360) */ + uint32_t seek_size; + + if (!is_id32be(offset,sf, "XMA2")) + goto fail; + offset += 0x04; + + xma2_size = read_u32be(offset+0x00,sf); + seek_size = read_u32be(offset+0x04,sf); + data_size = read_u32be(offset+0x08,sf); + /* 0x0c: ? */ + xma2_offset = offset+0x10; + if (!read_u8(xma2_offset+0x00, sf)) /* needs "xma2" chunk (Spider-Man 4 beta has multi-streams) */ + goto fail; + + /* loops never set */ + xma2_parse_xma2_chunk(sf, xma2_offset, &channels, &sample_rate, &loop_flag, &num_samples, NULL, NULL); + + start_offset = offset + 0x10 + xma2_size + seek_size; break; + } default: - VGM_LOG("P3D: unknown codec 0x%04x\n", codec); + vgm_logi("P3D: unknown codec 0x%04x\n", codec); goto fail; } - if (start_offset + data_size != file_size) goto fail; + if (start_offset + data_size != file_size) + goto fail; + /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); + vgmstream = allocate_vgmstream(channels, loop_flag); if (!vgmstream) goto fail; + vgmstream->meta_type = meta_P3D; vgmstream->sample_rate = sample_rate; vgmstream->num_samples = num_samples; - vgmstream->meta_type = meta_P3D; if (name_offset) - read_string(vgmstream->stream_name,STREAM_NAME_SIZE, name_offset,streamFile); + read_string(vgmstream->stream_name,STREAM_NAME_SIZE, name_offset,sf); - /* codec init */ switch(codec) { case 0x72616470: /* "radp" (PC) */ vgmstream->coding_type = coding_RAD_IMA_mono; @@ -149,7 +162,7 @@ VGMSTREAM * init_vgmstream_p3d(STREAMFILE *streamFile) { cfg.data_size = data_size; /* block_size * 3 = frame size (0x60*3=0x120 or 0x40*3=0xC0) but doesn't seem to have any significance) */ - vgmstream->codec_data = init_mpeg_custom(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_P3D, &cfg); + vgmstream->codec_data = init_mpeg_custom(sf, start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_P3D, &cfg); if (!vgmstream->codec_data) goto fail; vgmstream->layout_type = layout_none; break; @@ -161,23 +174,24 @@ VGMSTREAM * init_vgmstream_p3d(STREAMFILE *streamFile) { uint8_t buf[0x100]; size_t bytes; - bytes = ffmpeg_make_riff_xma2(buf,0x100, vgmstream->num_samples, data_size, vgmstream->channels, vgmstream->sample_rate, block_count, block_size); - vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,data_size); - if ( !vgmstream->codec_data ) goto fail; + //TODO: some in Spider-Man 4 beta use 18ch but ffmpeg supports max 16ch XMA2 + bytes = ffmpeg_make_riff_xma2_from_xma2_chunk(buf, sizeof(buf), xma2_offset, xma2_size, data_size, sf); + vgmstream->codec_data = init_ffmpeg_header_offset(sf, buf,bytes, start_offset,data_size); + if (!vgmstream->codec_data) goto fail; vgmstream->coding_type = coding_FFmpeg; vgmstream->layout_type = layout_none; - xma_fix_raw_samples(vgmstream, streamFile, start_offset, data_size, 0, 1,1); /* samples needs adjustment */ + xma_fix_raw_samples(vgmstream, sf, start_offset, data_size, 0, 1,1); /* samples needs adjustment */ break; } #endif default: - VGM_LOG("P3D: unknown codec 0x%04x\n", codec); + vgm_logi("P3D: unknown codec 0x%04x\n", codec); goto fail; } - if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) + if (!vgmstream_open_stream(vgmstream, sf, start_offset)) goto fail; return vgmstream; From 91e12ab55966a1c81156ad75d515971ea564413f Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 12 Sep 2021 20:03:38 +0200 Subject: [PATCH 3/9] Fix some .ktsl2asbin/atsl [Nioh (PC)] --- src/meta/atsl.c | 302 +++++++++++++++++++++++------------------------- src/meta/ktsr.c | 66 +++++------ 2 files changed, 178 insertions(+), 190 deletions(-) diff --git a/src/meta/atsl.c b/src/meta/atsl.c index 0b2f6c5b..13cf94d0 100644 --- a/src/meta/atsl.c +++ b/src/meta/atsl.c @@ -1,157 +1,145 @@ -#include "meta.h" -#include "../coding/coding.h" - -typedef enum { ATRAC3, ATRAC9, KOVS, KTSS, KTAC } atsl_codec; - -/* .ATSL - Koei Tecmo audio container [One Piece Pirate Warriors (PS3), Warriors All-Stars (PC)] */ -VGMSTREAM * init_vgmstream_atsl(STREAMFILE *streamFile) { - VGMSTREAM *vgmstream = NULL; - STREAMFILE *temp_streamFile = NULL; - int total_subsongs, target_subsong = streamFile->stream_index; - int type, big_endian = 0, entries; - atsl_codec codec; - const char* fake_ext; - off_t subfile_offset = 0; - size_t subfile_size = 0, header_size, entry_size; - int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL; - - - /* checks */ - /* .atsl: header id (for G1L extractions), .atsl3: PS3 games, .atsl4: PS4 games */ - if ( !check_extensions(streamFile,"atsl,atsl3,atsl4")) - goto fail; - if (read_32bitBE(0x00,streamFile) != 0x4154534C) /* "ATSL" */ - goto fail; - - /* main header (LE) */ - header_size = read_32bitLE(0x04,streamFile); - /* 0x08/0c: flags?, 0x10: fixed? (0x03E8) */ - entries = read_32bitLE(0x14,streamFile); - /* 0x18: 0x28, or 0x30 (rarer) */ - /* 0x1c: null, 0x20: subheader size, 0x24/28: null */ - - /* Type byte may be wrong (could need header id tests instead). Example flags at 0x08/0x0c: - * - 00010101 00020001 .atsl3 from One Piece Pirate Warriors (PS3)[ATRAC3] - * - 00000201 00020001 .atsl3 from Fist of North Star: Ken's Rage 2 (PS3)[ATRAC3] - * 00000301 00020101 (same) - * - 01040301 00060301 .atsl4 from Nobunaga's Ambition: Sphere of Influence (PS4)[ATRAC9] - * - 00060301 00040301 atsl in G1L from One Piece Pirate Warriors 3 (Vita)[ATRAC9] - * - 00060301 00010301 atsl in G1L from One Piece Pirate Warriors 3 (PC)[KOVS] - * - 000A0301 00010501 atsl in G1L from Warriors All-Stars (PC)[KOVS] - * - 000B0301 00080601 atsl in G1l from Sengoku Musou Sanada Maru (Switch)[KTSS] - * - 010C0301 01060601 .atsl from Dynasty Warriors 9 (PS4)[KTAC] - */ - entry_size = 0x28; - type = read_16bitLE(0x0c, streamFile); - switch(type) { - case 0x0100: - codec = KOVS; - fake_ext = "kvs"; - break; - case 0x0200: - codec = ATRAC3; - fake_ext = "at3"; - big_endian = 1; - break; - case 0x0400: - case 0x0600: - codec = ATRAC9; - fake_ext = "at9"; - break; - case 0x0601: - codec = KTAC; - fake_ext = "ktac"; - entry_size = 0x3c; - break; - case 0x0800: - codec = KTSS; - fake_ext = "ktss"; - break; - default: - VGM_LOG("ATSL: unknown type %x\n", type); - goto fail; - } - read_32bit = big_endian ? read_32bitBE : read_32bitLE; - - - /* entries can point to the same file, count unique only */ - { - int i,j; - - total_subsongs = 0; - if (target_subsong == 0) target_subsong = 1; - - /* parse entry header (in machine endianness) */ - for (i = 0; i < entries; i++) { - int is_unique = 1; - - /* 0x00: id */ - off_t entry_subfile_offset = read_32bit(header_size + i*entry_size + 0x04,streamFile); - size_t entry_subfile_size = read_32bit(header_size + i*entry_size + 0x08,streamFile); - /* 0x08+: channels/sample rate/num_samples/loop_start/etc (match subfile header) */ - - /* check if current entry was repeated in a prev entry */ - for (j = 0; j < i; j++) { - off_t prev_offset = read_32bit(header_size + j*entry_size + 0x04,streamFile); - if (prev_offset == entry_subfile_offset) { - is_unique = 0; - break; - } - } - if (!is_unique) - continue; - - total_subsongs++; - - /* target GET, but keep going to count subsongs */ - if (!subfile_offset && target_subsong == total_subsongs) { - subfile_offset = entry_subfile_offset; - subfile_size = entry_subfile_size; - } - } - } - if (target_subsong > total_subsongs || total_subsongs <= 0) goto fail; - if (!subfile_offset || !subfile_size) goto fail; - - - /* some kind of seek/switch table may follow (optional, found in .atsl3) */ - - - temp_streamFile = setup_subfile_streamfile(streamFile, subfile_offset,subfile_size, fake_ext); - if (!temp_streamFile) goto fail; - - /* init the VGMSTREAM */ - switch(codec) { - case ATRAC3: - case ATRAC9: - vgmstream = init_vgmstream_riff(temp_streamFile); - if (!vgmstream) goto fail; - break; -#ifdef VGM_USE_VORBIS - case KOVS: - vgmstream = init_vgmstream_ogg_vorbis(temp_streamFile); - if (!vgmstream) goto fail; - break; -#endif - case KTSS: - vgmstream = init_vgmstream_ktss(temp_streamFile); - if (!vgmstream) goto fail; - break; - case KTAC: - //vgmstream = init_vgmstream_ktac(temp_streamFile); //Koei Tecto VBR-like ATRAC9 - //if (!vgmstream) goto fail; - //break; - default: - goto fail; - } - - vgmstream->num_streams = total_subsongs; - - close_streamfile(temp_streamFile); - return vgmstream; - -fail: - close_streamfile(temp_streamFile); - close_vgmstream(vgmstream); - return NULL; -} +#include "meta.h" +#include "../coding/coding.h" + + +/* .ATSL - Koei Tecmo audio container [One Piece Pirate Warriors (PS3), Warriors All-Stars (PC)] */ +VGMSTREAM* init_vgmstream_atsl(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; + STREAMFILE* temp_sf = NULL; + int total_subsongs, target_subsong = sf->stream_index; + int type, big_endian = 0, entries; + uint32_t subfile_offset = 0, subfile_size = 0, header_size, entry_size; + + VGMSTREAM* (*init_vgmstream)(STREAMFILE* sf) = NULL; + const char* fake_ext; + + + /* checks */ + if (!is_id32be(0x00,sf, "ATSL")) + goto fail; + /* .atsl: header id (for G1L extractions), .atsl3: PS3 games, .atsl4: PS4 games */ + if (!check_extensions(sf,"atsl,atsl3,atsl4")) + goto fail; + + /* main header (LE) */ + header_size = read_u32le(0x04,sf); + /* 0x08/0c: flags? */ + /* 0x10: volume? (always 1000) */ + entries = read_u32le(0x14,sf); + /* 0x18: 0x28, or 0x30 (rarer) */ + /* 0x1c: null */ + /* 0x20: subheader size */ + /* 0x24/28: null */ + + /* Type byte may be wrong (could need header id tests instead). Example flags at 0x08/0x0c: + * - 00010101 00020001 .atsl3 from One Piece Pirate Warriors (PS3)[ATRAC3] + * - 00000201 00020001 .atsl3 from Fist of North Star: Ken's Rage 2 (PS3)[ATRAC3] + * 00000301 00020101 (same) + * - 01040301 00060301 .atsl4 from Nobunaga's Ambition: Sphere of Influence (PS4)[ATRAC9] + * - 00060301 00040301 atsl in G1L from One Piece Pirate Warriors 3 (Vita)[ATRAC9] + * - 00060301 00010301 atsl in G1L from One Piece Pirate Warriors 3 (PC)[KOVS] + * - 000A0301 00010501 atsl in G1L from Warriors All-Stars (PC)[KOVS] + * - 000B0301 00080601 atsl in G1l from Sengoku Musou Sanada Maru (Switch)[KTSS] + * - 010C0301 01060601 .atsl from Dynasty Warriors 9 (PS4)[KTAC] + * - 01000000 01010501 .atsl from Nioh (PC)[KOVS] + * - 01000000 00010501 .atsl from Nioh (PC)[KOVS] + */ + + type = read_u16le(0x0c, sf); + switch(type) { + case 0x0100: /* KOVS */ + init_vgmstream = init_vgmstream_ogg_vorbis; + fake_ext = "kvs"; + entry_size = 0x28; + break; + case 0x0101: + init_vgmstream = init_vgmstream_ogg_vorbis; + fake_ext = "kvs"; + entry_size = 0x3c; + break; + case 0x0200: /* ATRAC3 */ + init_vgmstream = init_vgmstream_riff; + fake_ext = "at3"; + entry_size = 0x28; + big_endian = 1; + break; + case 0x0400: + case 0x0600: /* ATRAC9 */ + init_vgmstream = init_vgmstream_riff; + fake_ext = "at9"; + entry_size = 0x28; + break; + case 0x0601: /* KTAC */ + init_vgmstream = init_vgmstream_ktac; + fake_ext = "ktac"; + entry_size = 0x3c; + break; + case 0x0800: /* KTSS */ + init_vgmstream = init_vgmstream_ktss; + fake_ext = "ktss"; + entry_size = 0x28; + break; + default: + vgm_logi("ATSL: unknown type %x (report)\n", type); + goto fail; + } + + /* entries can point to the same file, count unique only */ + { + int i, j; + uint32_t (*read_u32)(off_t,STREAMFILE*) = big_endian ? read_u32be : read_u32le; + + total_subsongs = 0; + if (target_subsong == 0) target_subsong = 1; + + /* parse entry header (in machine endianness) */ + for (i = 0; i < entries; i++) { + int is_unique = 1; + + /* 0x00: id */ + uint32_t entry_subfile_offset = read_u32(header_size + i*entry_size + 0x04,sf); + uint32_t entry_subfile_size = read_u32(header_size + i*entry_size + 0x08,sf); + /* 0x08+: channels/sample rate/num_samples/loop_start/etc (match subfile header) */ + + /* check if current entry was repeated in a prev entry */ + for (j = 0; j < i; j++) { + off_t prev_offset = read_u32(header_size + j*entry_size + 0x04,sf); + if (prev_offset == entry_subfile_offset) { + is_unique = 0; + break; + } + } + if (!is_unique) + continue; + + total_subsongs++; + + /* target GET, but keep going to count subsongs */ + if (!subfile_offset && target_subsong == total_subsongs) { + subfile_offset = entry_subfile_offset; + subfile_size = entry_subfile_size; + } + } + } + if (target_subsong > total_subsongs || total_subsongs <= 0) goto fail; + if (!subfile_offset || !subfile_size) goto fail; + + /* some kind of seek/switch table may follow (optional, found in .atsl3) */ + + temp_sf = setup_subfile_streamfile(sf, subfile_offset, subfile_size, fake_ext); + if (!temp_sf) goto fail; + + /* init the VGMSTREAM */ + vgmstream = init_vgmstream(temp_sf); + if (!vgmstream) goto fail; + + vgmstream->num_streams = total_subsongs; + + close_streamfile(temp_sf); + return vgmstream; + +fail: + close_streamfile(temp_sf); + close_vgmstream(vgmstream); + return NULL; +} diff --git a/src/meta/ktsr.c b/src/meta/ktsr.c index c74d6972..acecbf5f 100644 --- a/src/meta/ktsr.c +++ b/src/meta/ktsr.c @@ -38,26 +38,25 @@ static layered_layout_data* build_layered_atrac9(ktsr_header* ktsr, STREAMFILE * /* KTSR - Koei Tecmo sound resource countainer */ VGMSTREAM* init_vgmstream_ktsr(STREAMFILE* sf) { VGMSTREAM* vgmstream = NULL; - STREAMFILE *sf_b = NULL; + STREAMFILE* sf_b = NULL; ktsr_header ktsr = {0}; int target_subsong = sf->stream_index; int separate_offsets = 0; /* checks */ + if (!is_id32be(0x00, sf, "KTSR")) + goto fail; + if (read_u32be(0x04, sf) != 0x777B481A) /* hash(?) id: 0x777B481A=as, 0x0294DDFC=st, 0xC638E69E=gc */ + goto fail; /* .ktsl2asbin: common [Atelier Ryza (PC/Switch), Nioh (PC)] */ if (!check_extensions(sf, "ktsl2asbin")) goto fail; /* KTSR can be a memory file (ktsl2asbin), streams (ktsl2stbin) and global config (ktsl2gcbin) - * This accepts ktsl2asbin with internal data, or opening external streams as subsongs. + * This accepts .ktsl2asbin with internal data or external streams as subsongs. * Some info from KTSR.bt */ - if (!is_id32be(0x00, sf, "KTSR")) - goto fail; - if (read_u32be(0x04, sf) != 0x777B481A) /* hash(?) id: 0x777B481A=as, 0x0294DDFC=st, 0xC638E69E=gc */ - goto fail; - if (target_subsong == 0) target_subsong = 1; ktsr.target_subsong = target_subsong; @@ -68,7 +67,7 @@ VGMSTREAM* init_vgmstream_ktsr(STREAMFILE* sf) { if (ktsr.is_external) { sf_b = open_streamfile_by_ext(sf, "ktsl2stbin"); if (!sf_b) { - VGM_LOG("KTSR: companion file not found\n"); + vgm_logi("KTSR: companion file '*.ktsl2stbin' not found\n"); goto fail; } } @@ -129,28 +128,23 @@ VGMSTREAM* init_vgmstream_ktsr(STREAMFILE* sf) { #ifdef VGM_USE_VORBIS case KVS: { - VGMSTREAM *ogg_vgmstream = NULL; //TODO: meh - STREAMFILE *sf_kvs = setup_subfile_streamfile(sf_b, ktsr.stream_offsets[0], ktsr.stream_sizes[0], "kvs"); - if (!sf_kvs) goto fail; + VGMSTREAM* ogg_vgmstream = NULL; //TODO: meh + STREAMFILE* temp_sf = setup_subfile_streamfile(sf_b, ktsr.stream_offsets[0], ktsr.stream_sizes[0], "kvs"); + if (!temp_sf) goto fail; - ogg_vgmstream = init_vgmstream_ogg_vorbis(sf_kvs); - close_streamfile(sf_kvs); - if (ogg_vgmstream) { - ogg_vgmstream->stream_size = vgmstream->stream_size; - ogg_vgmstream->num_streams = vgmstream->num_streams; - ogg_vgmstream->channel_layout = vgmstream->channel_layout; - /* loops look shared */ - strcpy(ogg_vgmstream->stream_name, vgmstream->stream_name); + ogg_vgmstream = init_vgmstream_ogg_vorbis(temp_sf); + close_streamfile(temp_sf); + if (!ogg_vgmstream) goto fail; - close_vgmstream(vgmstream); - if (sf_b != sf) close_streamfile(sf_b); - return ogg_vgmstream; - } - else { - goto fail; - } + ogg_vgmstream->stream_size = vgmstream->stream_size; + ogg_vgmstream->num_streams = vgmstream->num_streams; + ogg_vgmstream->channel_layout = vgmstream->channel_layout; + /* loops look shared */ + strcpy(ogg_vgmstream->stream_name, vgmstream->stream_name); - break; + close_vgmstream(vgmstream); + if (sf_b != sf) close_streamfile(sf_b); + return ogg_vgmstream; } #endif @@ -158,7 +152,6 @@ VGMSTREAM* init_vgmstream_ktsr(STREAMFILE* sf) { goto fail; } - if (!vgmstream_open_stream_bf(vgmstream, sf_b, ktsr.stream_offsets[0], 1)) goto fail; @@ -282,13 +275,14 @@ static int parse_ktsr_subfile(ktsr_header* ktsr, STREAMFILE* sf, off_t offset) { int i; uint32_t type; - type = read_u32be(offset + 0x00, sf); + type = read_u32be(offset + 0x00, sf); /* hash-id? */ //size = read_u32le(offset + 0x04, sf); /* probably could check the flag in sound header, but the format is kinda messy */ - switch(type) { /* hash-id? */ + switch(type) { case 0x38D0437D: /* external [Nioh (PC), Atelier Ryza (PC)] */ + case 0x3DEA478D: /* external [Nioh (PC)] */ case 0xDF92529F: /* external [Atelier Ryza (PC)] */ case 0x6422007C: /* external [Atelier Ryza (PC)] */ /* 08 subtype? (ex. 0x522B86B9) @@ -311,10 +305,16 @@ static int parse_ktsr_subfile(ktsr_header* ktsr, STREAMFILE* sf, off_t offset) { ktsr->format = read_u32le(offset + 0x14, sf); /* other fields will be read in the external stream */ - ktsr->channel_layout= read_u32le(offset + 0x28, sf); + ktsr->channel_layout = read_u32le(offset + 0x28, sf); - ktsr->stream_offsets[0] = read_u32le(offset + 0x34, sf); - ktsr->stream_sizes[0] = read_u32le(offset + 0x38, sf); + if (type == 0x3DEA478D) { /* Nioh (PC) has one less field, some files only [ABS.ktsl2asbin] */ + ktsr->stream_offsets[0] = read_u32le(offset + 0x30, sf); + ktsr->stream_sizes[0] = read_u32le(offset + 0x34, sf); + } + else { + ktsr->stream_offsets[0] = read_u32le(offset + 0x34, sf); + ktsr->stream_sizes[0] = read_u32le(offset + 0x38, sf); + } ktsr->is_external = 1; if (ktsr->format != 0x05) { From 518cf8f8b1c5db25056c2992199cbeae5b0cd418 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 12 Sep 2021 20:05:56 +0200 Subject: [PATCH 4/9] build: fix some emscripten/wasm crashes --- src/streamfile.c | 55 +++++++++++++++++++++++++++++++----------------- src/streamfile.h | 6 +++--- 2 files changed, 39 insertions(+), 22 deletions(-) diff --git a/src/streamfile.c b/src/streamfile.c index 54399eed..18586cc5 100644 --- a/src/streamfile.c +++ b/src/streamfile.c @@ -2,6 +2,10 @@ #include "util.h" #include "vgmstream.h" +/* for dup/fdopen in some systems */ +#ifndef _MSC_VER + #include +#endif /* MSVC fixes (though mingw uses MSVCRT but not MSC_VER, maybe use AND?) */ #if defined(__MSVCRT__) || defined(_MSC_VER) @@ -15,6 +19,7 @@ #define ftello ftell #endif */ + #define fseek_v _fseeki64 //fseek/fseeko #define ftell_v _ftelli64 //ftell/ftello @@ -34,7 +39,7 @@ #define ftell_v ftell #else #define fseek_v fseeko64 //fseeko - #define ftell_v ftello64 //ftelloo + #define ftell_v ftello64 //ftello #endif @@ -48,7 +53,7 @@ typedef struct { 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 valid_size; /* current buffer size */ size_t file_size; /* buffered file size */ } STDIO_STREAMFILE; @@ -154,12 +159,6 @@ 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 stdio_close(STDIO_STREAMFILE* sf) { - if (sf->infile) - fclose(sf->infile); - free(sf->buf); - free(sf); -} static STREAMFILE* stdio_open(STDIO_STREAMFILE* sf, const char* const filename, size_t buf_size) { if (!filename) @@ -187,11 +186,19 @@ static STREAMFILE* stdio_open(STDIO_STREAMFILE* sf, const char* const filename, /* on failure just close and try the default path (which will probably fail a second time) */ } -#endif +#endif // a normal open, open a new file return open_stdio_streamfile_buffer(filename, buf_size); } +static void stdio_close(STDIO_STREAMFILE* sf) { + if (sf->infile) + fclose(sf->infile); + free(sf->buf); + free(sf); +} + + 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; @@ -360,10 +367,12 @@ static offv_t buffer_get_offset(BUFFER_STREAMFILE* sf) { 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* 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* sf) { sf->inner_sf->close(sf->inner_sf); free(sf->buf); @@ -435,12 +444,14 @@ static size_t wrap_get_size(WRAP_STREAMFILE* sf) { 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* sf, char* name, size_t name_len) { - sf->inner_sf->get_name(sf->inner_sf, name, name_len); /* default */ +static void wrap_get_name(WRAP_STREAMFILE* sf, char* name, size_t name_size) { + sf->inner_sf->get_name(sf->inner_sf, name, name_size); /* default */ } -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 STREAMFILE* wrap_open(WRAP_STREAMFILE* sf, const char* const filename, size_t buf_size) { + return sf->inner_sf->open(sf->inner_sf, filename, buf_size); /* default (don't call open_wrap_streamfile) */ } + static void wrap_close(WRAP_STREAMFILE* sf) { //sf->inner_sf->close(sf->inner_sf); /* don't close */ free(sf); @@ -503,9 +514,10 @@ static size_t clamp_get_size(CLAMP_STREAMFILE* sf) { 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* sf, char* name, size_t name_len) { - sf->inner_sf->get_name(sf->inner_sf, name, name_len); /* default */ +static void clamp_get_name(CLAMP_STREAMFILE* sf, char* name, size_t name_size) { + sf->inner_sf->get_name(sf->inner_sf, name, name_size); /* default */ } + 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; @@ -520,6 +532,7 @@ static STREAMFILE* clamp_open(CLAMP_STREAMFILE* sf, const char* const filename, return new_inner_sf; } } + static void clamp_close(CLAMP_STREAMFILE* sf) { sf->inner_sf->close(sf->inner_sf); free(sf); @@ -582,13 +595,15 @@ static size_t io_get_size(IO_STREAMFILE* sf) { 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* sf, char* name, size_t name_len) { - sf->inner_sf->get_name(sf->inner_sf, name, name_len); /* default */ +static void io_get_name(IO_STREAMFILE* sf, char* name, size_t name_size) { + sf->inner_sf->get_name(sf->inner_sf, name, name_size); /* default */ } + 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* sf) { if (sf->close_callback) sf->close_callback(sf->inner_sf, sf->data); @@ -633,7 +648,7 @@ STREAMFILE* open_io_streamfile_ex(STREAMFILE* sf, void* data, size_t data_size, } return &this_sf->vt; - + fail: if (this_sf) free(this_sf->data); free(this_sf); @@ -676,6 +691,7 @@ static void fakename_get_name(FAKENAME_STREAMFILE* sf, char* name, size_t name_s strncpy(name,sf->fakename, name_size); name[name_size - 1] = '\0'; } + static STREAMFILE* fakename_open(FAKENAME_STREAMFILE* sf, const char* const filename, size_t buf_size) { /* detect re-opening the file */ if (strcmp(filename, sf->fakename) == 0) { @@ -797,6 +813,7 @@ static offv_t multifile_get_offset(MULTIFILE_STREAMFILE* sf) { 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* sf, const char* const filename, size_t buf_size) { char original_filename[PATH_LIMIT]; STREAMFILE* new_sf = NULL; @@ -1219,7 +1236,7 @@ STREAMFILE* read_filemap_file_pos(STREAMFILE* sf, int file_num, int* p_pos) { /* get key/val (ignores lead/trailing spaces, stops at comment/separator) */ ok = sscanf(line, " %[^\t#:] : %[^\t#\r\n] ", key, val); if (ok != 2) { /* ignore line if no key=val (comment or garbage) */ - continue; + continue; } if (strcmp(key, filename) == 0) { diff --git a/src/streamfile.h b/src/streamfile.h index c85a25ba..1aa46d92 100644 --- a/src/streamfile.h +++ b/src/streamfile.h @@ -66,16 +66,16 @@ typedef struct _STREAMFILE { size_t (*get_size)(struct _STREAMFILE* sf); //todo: DO NOT USE, NOT RESET PROPERLY (remove?) - offv_t (*get_offset)(struct _STREAMFILE*); + offv_t (*get_offset)(struct _STREAMFILE* sf); /* 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); + struct _STREAMFILE* (*open)(struct _STREAMFILE* sf, const char* const filename, size_t buf_size); /* free current STREAMFILE */ - void (*close)(struct _STREAMFILE*); + void (*close)(struct _STREAMFILE* sf); /* Substream selection for formats with subsongs. * Not ideal here, but it was the simplest way to pass to all init_vgmstream_x functions. */ From e1c9da8beabf0334459f575f2dfbd07463e3b1e7 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 12 Sep 2021 20:08:38 +0200 Subject: [PATCH 5/9] build: cmake tweak for ffmpeg --- CMakeLists.txt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index aa0e2e55..bb5d9aa4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -103,10 +103,11 @@ endif() if(BUILD_STATIC) set(BUILD_SHARED_LIBS OFF) set(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++ -static") - - find_package(PkgConfig REQUIRED) - pkg_check_modules(PC_OPUS REQUIRED opus>=1.1) - + + # it is already kind of obvious when you do not have it, and just prevents you from building without ffmpeg + #find_package(PkgConfig REQUIRED) + #pkg_check_modules(PC_OPUS REQUIRED opus>=1.1) + # Incompatible with static builds set(BUILD_AUDACIOUS OFF) endif() From ea910e2ad2fb9e4f43b67da5f2cda5b5db119738 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 12 Sep 2021 20:08:55 +0200 Subject: [PATCH 6/9] acb: log/tweaks --- src/meta/acb.c | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/src/meta/acb.c b/src/meta/acb.c index 69737494..12f5eb78 100644 --- a/src/meta/acb.c +++ b/src/meta/acb.c @@ -7,15 +7,15 @@ VGMSTREAM* init_vgmstream_acb(STREAMFILE* sf) { VGMSTREAM* vgmstream = NULL; STREAMFILE* temp_sf = NULL; - off_t subfile_offset; - size_t subfile_size; - utf_context *utf = NULL; + uint32_t subfile_offset; + uint32_t subfile_size; + utf_context* utf = NULL; /* checks */ - if (!check_extensions(sf, "acb")) + if (!is_id32be(0x00,sf, "@UTF")) goto fail; - if (read_u32be(0x00,sf) != 0x40555446) /* "@UTF" */ + if (!check_extensions(sf, "acb")) goto fail; /* .acb is a cue sheet that uses @UTF (CRI's generic table format) to store row/columns @@ -41,8 +41,10 @@ VGMSTREAM* init_vgmstream_acb(STREAMFILE* sf) { subfile_size = size; /* column exists but can be empty */ - if (subfile_size == 0) + if (subfile_size == 0) { + vgm_logi("ACB: bank has no subsongs (ignore)\n"); goto fail; + } } //;VGM_LOG("ACB: subfile offset=%lx + %x\n", subfile_offset, subfile_size); @@ -50,7 +52,7 @@ VGMSTREAM* init_vgmstream_acb(STREAMFILE* sf) { temp_sf = setup_subfile_streamfile(sf, subfile_offset,subfile_size, "awb"); if (!temp_sf) goto fail; - if (read_u32be(0x00, temp_sf) == 0x43504B20) { /* "CPK " */ + if (is_id32be(0x00, temp_sf, "CPK ")) { vgmstream = init_vgmstream_cpk_memory(temp_sf, sf); /* older */ if (!vgmstream) goto fail; } @@ -107,17 +109,17 @@ typedef struct { STREAMFILE* acbFile; /* original reference, don't close */ /* keep track of these tables so they can be closed when done */ - utf_context *Header; + utf_context* Header; - utf_context *CueNameTable; - utf_context *CueTable; - utf_context *BlockSequenceTable; - utf_context *BlockTable; - utf_context *SequenceTable; - utf_context *TrackTable; - utf_context *TrackCommandTable; - utf_context *SynthTable; - utf_context *WaveformTable; + utf_context* CueNameTable; + utf_context* CueTable; + utf_context* BlockSequenceTable; + utf_context* BlockTable; + utf_context* SequenceTable; + utf_context* TrackTable; + utf_context* TrackCommandTable; + utf_context* SynthTable; + utf_context* WaveformTable; STREAMFILE* CueNameSf; STREAMFILE* CueSf; @@ -142,7 +144,7 @@ typedef struct { /* name stuff */ int16_t cuename_index; - const char * cuename_name; + const char* cuename_name; int awbname_count; int16_t awbname_list[ACB_MAX_NAMELIST]; char name[ACB_MAX_NAME]; From 4bdb43e7772e4a8d85ad65c1590defbe154da3d9 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 12 Sep 2021 20:09:06 +0200 Subject: [PATCH 7/9] doc --- README.md | 2 +- src/meta/ubi_lyn_streamfile.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d5c82e20..6f86832f 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ You may compile them from source as well (see *build guide*). ### Linux Generally you need to build vgmstream's components manually (see *build guide*). For -a quick build call `/make-build-cmake.sh` (for Debian/Ubuntu-style distros, installs +a quick build call `./make-build-cmake.sh` (for Debian/Ubuntu-style distros, installs various deps first so you may prefer to call commands manually). Releases also distribute a static version of the CLI tool (kernel v3.2+). diff --git a/src/meta/ubi_lyn_streamfile.h b/src/meta/ubi_lyn_streamfile.h index ecef0f6d..cdcad0d7 100644 --- a/src/meta/ubi_lyn_streamfile.h +++ b/src/meta/ubi_lyn_streamfile.h @@ -6,7 +6,7 @@ static STREAMFILE* setup_ubi_lyn_streamfile(STREAMFILE* sf, off_t stream_offset, size_t interleave_size, int stream_number, int stream_count, size_t logical_size) { STREAMFILE *new_sf = NULL; deblock_config_t cfg = {0}; -VGM_LOG("so=%lx, chu=%x, n=%i, c=%i, lo=%x\n", stream_offset, interleave_size, stream_number, stream_count, logical_size); + cfg.stream_start = stream_offset; cfg.chunk_size = interleave_size; cfg.step_start = stream_number; From 3fe5967764cdc999bc7a100b331daab8097e30d0 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 12 Sep 2021 20:49:40 +0200 Subject: [PATCH 8/9] build: fix missing ifdef --- src/meta/atsl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/meta/atsl.c b/src/meta/atsl.c index 13cf94d0..fb12d0fa 100644 --- a/src/meta/atsl.c +++ b/src/meta/atsl.c @@ -47,6 +47,7 @@ VGMSTREAM* init_vgmstream_atsl(STREAMFILE* sf) { type = read_u16le(0x0c, sf); switch(type) { +#ifdef VGM_USE_VORBIS case 0x0100: /* KOVS */ init_vgmstream = init_vgmstream_ogg_vorbis; fake_ext = "kvs"; @@ -57,6 +58,7 @@ VGMSTREAM* init_vgmstream_atsl(STREAMFILE* sf) { fake_ext = "kvs"; entry_size = 0x3c; break; +#endif case 0x0200: /* ATRAC3 */ init_vgmstream = init_vgmstream_riff; fake_ext = "at3"; From b0ee80e21ca556ac4aa5261280c5a3c46ba138b2 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 12 Sep 2021 21:29:07 +0200 Subject: [PATCH 9/9] build: skip missing fseek64 on emscripten --- doc/BUILD.md | 25 +++++++++++++++++++++++++ src/streamfile.c | 31 ++++++++++++++++++++++++++----- 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/doc/BUILD.md b/doc/BUILD.md index 4127a5e8..b8d93f4e 100644 --- a/doc/BUILD.md +++ b/doc/BUILD.md @@ -362,6 +362,31 @@ For integration and "API" usage, easiest would be checking how `vgmstream_cli.c` A cleaner API/.h and build methods is planned for the future (low priority though). +# emscripten / wasm +It's possible to build vgmstream components with emscripten (in-browser support). + +Follow emscripten's installation instructions: +- https://emscripten.org/docs/getting_started/downloads.html +- https://emscripten.org/docs/compiling/Building-Projects.html#building-projects + +Then should be buildable on Linux (Windows should be possible too but has some issues at the moment), for example: +``` +git clone https://github.com/vgmstream/vgmstream +cd vgmstream +mkdir -p build && cd build + +# quickest example, some can be enabled +emcmake cmake -DBUILD_STATIC=ON -DUSE_JANSSON=OFF -DUSE_FFMPEG=OFF -DUSE_VORBIS=OFF -DUSE_MPEG=OFF -DUSE_G7221=OFF -DUSE_G719=OFF -DUSE_ATRAC9=OFF -DUSE_SPEEX=OFF -DUSE_MPEG=OFF -S .. -B . +emmake make +``` +Or with the base makefiles (may need to rename output to .js ATM): +``` +git clone https://github.com/vgmstream/vgmstream +cd vgmstream +make vgmstream-cli CC=emcc AR=emar strip=echo +``` + + ## External libraries Support for some codecs is done with external libs, instead of copying their code in vgmstream. There are various reasons for this: - each lib may have complex or conflicting ways to compile that aren't simple to replicate diff --git a/src/streamfile.c b/src/streamfile.c index 18586cc5..c3e4f90f 100644 --- a/src/streamfile.c +++ b/src/streamfile.c @@ -7,6 +7,18 @@ #include #endif +/* For (rarely needed) +2GB file support we use fseek64/ftell64. Those are usually available + * but may depend on compiler. + * - MSVC: +VS2008 should work + * - GCC/MingW: should be available + * - GCC/Linux: should be available but some systems may need __USE_FILE_OFFSET64, + * that we (probably) don't want since that turns off_t to off64_t + * - Clang: seems only defined on Linux/GNU environments, somehow emscripten is out + * (unsure about Clang Win since apparently they define _MSC_VER) + * - Android: API +24 if not using __USE_FILE_OFFSET64 + * Not sure if fopen64 is needed in some cases. May be work adding some compiler flag to control this manually. + */ + /* MSVC fixes (though mingw uses MSVCRT but not MSC_VER, maybe use AND?) */ #if defined(__MSVCRT__) || defined(_MSC_VER) #include @@ -20,8 +32,14 @@ #endif */ - #define fseek_v _fseeki64 //fseek/fseeko - #define ftell_v _ftelli64 //ftell/ftello + #define fopen_v fopen + #if (_MSC_VER >= 1400) + #define fseek_v _fseeki64 + #define ftell_v _ftelli64 + #else + #define fseek_v fseek + #define ftell_v ftell + #endif #ifdef fileno #undef fileno @@ -34,10 +52,13 @@ #define off_t __int64 #endif -#elif defined(XBMC) +#elif defined(XBMC) || defined(__EMSCRIPTEN__) || defined (__ANDROID__) + #define fopen_v fopen #define fseek_v fseek #define ftell_v ftell + #else + #define fopen_v fopen #define fseek_v fseeko64 //fseeko #define ftell_v ftello64 //ftello #endif @@ -252,7 +273,7 @@ static STREAMFILE* open_stdio_streamfile_buffer(const char* const filename, size FILE* infile = NULL; STREAMFILE* sf = NULL; - infile = fopen(filename,"rb"); + infile = fopen_v(filename,"rb"); if (!infile) { /* allow non-existing files in some cases */ if (!vgmstream_is_virtual_filename(filename)) @@ -1471,7 +1492,7 @@ void dump_streamfile(STREAMFILE* sf, int num) { get_streamfile_filename(sf, filename, sizeof(filename)); snprintf(dumpname, sizeof(dumpname), "%s_%02i.dump", filename, num); - f = fopen(dumpname,"wb"); + f = fopen_v(dumpname,"wb"); if (!f) return; }