From 92b5292d653e3f273b58bedfed8a6ee92a9a063e Mon Sep 17 00:00:00 2001 From: Martijn van Beurden Date: Tue, 31 Jan 2023 10:27:45 +0100 Subject: [PATCH] Restore compression type name to AIFF-C from foreign metadata --- src/flac/decode.c | 32 ++++++++++++++----------- src/flac/foreign_metadata.c | 47 +++++++++++++++++++++++++++---------- src/flac/foreign_metadata.h | 1 + 3 files changed, 54 insertions(+), 26 deletions(-) diff --git a/src/flac/decode.c b/src/flac/decode.c index c61c2a25..b7745363 100644 --- a/src/flac/decode.c +++ b/src/flac/decode.c @@ -113,7 +113,7 @@ static int DecoderSession_finish_error(DecoderSession *d); static FLAC__bool canonicalize_until_specification(utils__SkipUntilSpecification *spec, const char *inbasefilename, uint32_t sample_rate, FLAC__uint64 skip, FLAC__uint64 total_samples_in_input); static FLAC__bool write_iff_headers(FILE *f, DecoderSession *decoder_session, FLAC__uint64 samples); static FLAC__bool write_riff_wave_fmt_chunk_body(FILE *f, FLAC__bool is_waveformatextensible, uint32_t bps, uint32_t channels, uint32_t sample_rate, FLAC__uint32 channel_mask); -static FLAC__bool write_aiff_form_comm_chunk(FILE *f, FLAC__uint64 samples, uint32_t bps, uint32_t channels, uint32_t sample_rate, FileFormat format, FileSubFormat subformat); +static FLAC__bool write_aiff_form_comm_chunk(FILE *f, FLAC__uint64 samples, uint32_t bps, uint32_t channels, uint32_t sample_rate, FileFormat format, FileSubFormat subformat, FLAC__uint32 comm_length); static FLAC__bool write_little_endian_uint16(FILE *f, FLAC__uint16 val); static FLAC__bool write_little_endian_uint32(FILE *f, FLAC__uint32 val); static FLAC__bool write_little_endian_uint64(FILE *f, FLAC__uint64 val); @@ -700,7 +700,7 @@ FLAC__bool write_iff_headers(FILE *f, DecoderSession *decoder_session, FLAC__uin else if(format == FORMAT_AIFF) iff_size = 46 + foreign_metadata_size + aligned_data_size; else /* AIFF-C */ - iff_size = 52 + foreign_metadata_size + aligned_data_size; + iff_size = 16 + foreign_metadata_size + aligned_data_size + fm->aifc_comm_length; if(format != FORMAT_WAVE64 && format != FORMAT_RF64 && iff_size >= 0xFFFFFFF4) { flac__utils_printf(stderr, 1, "%s: ERROR: stream is too big to fit in a single %s file\n", decoder_session->inbasefilename, fmt_desc); @@ -847,7 +847,7 @@ FLAC__bool write_iff_headers(FILE *f, DecoderSession *decoder_session, FLAC__uin } } - if(!write_aiff_form_comm_chunk(f, samples, decoder_session->bps, decoder_session->channels, decoder_session->sample_rate, format, subformat)) + if(!write_aiff_form_comm_chunk(f, samples, decoder_session->bps, decoder_session->channels, decoder_session->sample_rate, format, subformat, fm?fm->aifc_comm_length:0)) return false; decoder_session->fm_offset2 = ftello(f); @@ -918,21 +918,23 @@ FLAC__bool write_riff_wave_fmt_chunk_body(FILE *f, FLAC__bool is_waveformatexten return true; } -FLAC__bool write_aiff_form_comm_chunk(FILE *f, FLAC__uint64 samples, uint32_t bps, uint32_t channels, uint32_t sample_rate, FileFormat format, FileSubFormat subformat) +FLAC__bool write_aiff_form_comm_chunk(FILE *f, FLAC__uint64 samples, uint32_t bps, uint32_t channels, uint32_t sample_rate, FileFormat format, FileSubFormat subformat, FLAC__uint32 comm_length) { + FLAC__uint32 i; FLAC__ASSERT(samples <= 0xffffffff); + if(comm_length == 0) { + if(format == FORMAT_AIFF) + comm_length = 30; + else + comm_length = 36; + } + if(flac__utils_fwrite("COMM", 1, 4, f) != 4) return false; - if(format == FORMAT_AIFF) { - if(!write_big_endian_uint32(f, 18)) /* chunk size = 18 */ - return false; - } - else { - if(!write_big_endian_uint32(f, 24)) /* chunk size = 24 */ - return false; - } + if(!write_big_endian_uint32(f, comm_length-12)) /* chunk size = 18 */ + return false; if(!write_big_endian_uint16(f, (FLAC__uint16)channels)) return false; @@ -955,8 +957,10 @@ FLAC__bool write_aiff_form_comm_chunk(FILE *f, FLAC__uint64 samples, uint32_t bp if(flac__utils_fwrite("sowt", 1, 4, f) != 4) return false; } - if(flac__utils_fwrite("\x00\x00", 1, 2, f) != 2) - return false; + for(i = 34; i < comm_length; i++) { + if(flac__utils_fwrite("\x00", 1, 1, f) != 1) + return false; + } } diff --git a/src/flac/foreign_metadata.c b/src/flac/foreign_metadata.c index d42e1499..2343769b 100644 --- a/src/flac/foreign_metadata.c +++ b/src/flac/foreign_metadata.c @@ -498,6 +498,7 @@ static FLAC__bool read_from_flac_(foreign_metadata_t *fm, FILE *f, FLAC__Metadat { FLAC__byte id[4], buffer[32]; FLAC__off_t offset; + FLAC__uint32 length; FLAC__bool first_block = true, type_found = false, ds64_found = false; FLAC__ASSERT(FLAC__STREAM_METADATA_APPLICATION_ID_LEN == sizeof(id)*8); @@ -522,6 +523,7 @@ static FLAC__bool read_from_flac_(foreign_metadata_t *fm, FILE *f, FLAC__Metadat else if(memcmp(id, FLAC__FOREIGN_METADATA_APPLICATION_ID[fm->type], sizeof(id))) continue; offset = FLAC__metadata_simple_iterator_get_block_offset(it); + length = FLAC__metadata_simple_iterator_get_block_length(it); /* skip over header and app ID */ offset += (FLAC__STREAM_METADATA_IS_LAST_LEN + FLAC__STREAM_METADATA_TYPE_LEN + FLAC__STREAM_METADATA_LENGTH_LEN) / 8; offset += sizeof(id); @@ -636,11 +638,12 @@ static FLAC__bool read_from_flac_(foreign_metadata_t *fm, FILE *f, FLAC__Metadat } fm->format_block = fm->num_blocks; if(fm->is_aifc) { - if(fread(buffer+4, 1, 28, f) != 28) { + if(fread(buffer+4, 1, 26, f) != 26) { if(error) *error = "read error (020)"; return false; } fm->is_sowt = 0 == memcmp(buffer+26, "sowt", 2); + fm->aifc_comm_length = length; } } else if(!memcmp(buffer, "SSND", 4)) { @@ -700,48 +703,68 @@ static FLAC__bool write_to_iff_(foreign_metadata_t *fm, FILE *fin, FILE *fout, F /* don't write first (RIFF/RF64/FORM) chunk, or ds64 chunk in the case of RF64, compare instead */ for(i = 0; i < (fm->is_rf64?2:1); i++) { if(fseeko(fin, fm->blocks[i].offset, SEEK_SET) < 0) { - if(error) *error = "seek failed in FLAC file (003)"; + if(error) *error = "seek failed in FLAC file"; return false; } - if(!compare_data_(fin, fout, fm->blocks[i].size, error, "read failed in WAVE/AIFF file (004)", "write failed in FLAC file (005)", "stored foreign metadata seems invalid")) + if(!compare_data_(fin, fout, fm->blocks[i].size, error, "read failed in FLAC file", "read failed in WAVE/AIFF file", "stored main chunk length differs from written length")) return false; } for(; i < fm->format_block; i++) { if(fseeko(fin, fm->blocks[i].offset, SEEK_SET) < 0) { - if(error) *error = "seek failed in FLAC file (003)"; + if(error) *error = "seek failed in FLAC file"; return false; } - if(!copy_data_(fin, fout, fm->blocks[i].size, error, "read failed in WAVE/AIFF file (004)", "write failed in FLAC file (005)")) + if(!copy_data_(fin, fout, fm->blocks[i].size, error, "read failed in FLAC file", "read failed in WAVE/AIFF file")) return false; } + + if(fm->is_aifc) { + /* Need to restore compression type name */ + if(fseeko(fout, 30, SEEK_CUR) < 0) { + if(error) *error = "seek failed in AIFF-C file"; + return false; + } + if(fseeko(fin, fm->blocks[i].offset+30, SEEK_SET) < 0) { + if(error) *error = "seek failed in FLAC file"; + return false; + } + if(!copy_data_(fin, fout, fm->aifc_comm_length-34, error, "read failed in FLAC file", "write failed in WAVE/AIFF file")) + return false; + /* Now seek back */ + if(fseeko(fout, ((FLAC__int32)(fm->aifc_comm_length) * -1) + 4, SEEK_CUR) < 0) { + if(error) *error = "seek failed in AIFF-C file"; + return false; + } + } + /* compare format block */ if(fseeko(fin, fm->blocks[i].offset, SEEK_SET) < 0) { - if(error) *error = "seek failed in FLAC file (003)"; + if(error) *error = "seek failed in FLAC file"; return false; } - if(!compare_data_(fin, fout, fm->blocks[i].size, error, "read failed in WAVE/AIFF file (004)", "write failed in FLAC file (005)", "stored foreign format block differs from written block. Perhaps the file is being restored to a different format than that of the original file")) + if(!compare_data_(fin, fout, fm->blocks[i].size, error, "read failed in FLAC file", "read failed in WAVE/AIFF file", "stored foreign format block differs from written block. Perhaps the file is being restored to a different format than that of the original file")) return false; i++; for(; i < fm->audio_block; i++) { if(fseeko(fin, fm->blocks[i].offset, SEEK_SET) < 0) { - if(error) *error = "seek failed in FLAC file (007)"; + if(error) *error = "seek failed in FLAC file"; return false; } - if(!copy_data_(fin, fout, fm->blocks[i].size, error, "read failed in WAVE/AIFF file (008)", "write failed in FLAC file (009)")) + if(!copy_data_(fin, fout, fm->blocks[i].size, error, "read failed in FLAC file", "write failed in WAVE/AIFF file")) return false; } if(fseeko(fout, offset3, SEEK_SET) < 0) { - if(error) *error = "seek failed in WAVE/AIFF file (010)"; + if(error) *error = "seek failed in WAVE/AIFF file"; return false; } for(i = fm->audio_block+1; i < fm->num_blocks; i++) { if(fseeko(fin, fm->blocks[i].offset, SEEK_SET) < 0) { - if(error) *error = "seek failed in FLAC file (011)"; + if(error) *error = "seek failed in FLAC file"; return false; } - if(!copy_data_(fin, fout, fm->blocks[i].size, error, "read failed in WAVE/AIFF file (012)", "write failed in FLAC file (013)")) + if(!copy_data_(fin, fout, fm->blocks[i].size, error, "read failed in FLAC file", "write failed in WAVE/AIFF file")) return false; } return true; diff --git a/src/flac/foreign_metadata.h b/src/flac/foreign_metadata.h index 7f24239a..365e6660 100644 --- a/src/flac/foreign_metadata.h +++ b/src/flac/foreign_metadata.h @@ -63,6 +63,7 @@ typedef struct { FLAC__bool is_wavefmtex; /* always false if type!=RIFF */ FLAC__bool is_aifc; /* always false if type!=AIFF */ FLAC__bool is_sowt; /* always false if type!=AIFF */ + FLAC__uint32 aifc_comm_length; FLAC__uint32 ssnd_offset_size; /* 0 if type!=AIFF */ } foreign_metadata_t;