From 578abcaf3b109dbd04ccbeff89fec8103fad05ff Mon Sep 17 00:00:00 2001 From: Abhijith Date: Mon, 16 Mar 2026 08:39:52 +0530 Subject: [PATCH] [FIX] Fix ownership of default Matroska track language (#2193) * Fix ownership of default Matroska track language * matroska: restore lang_ietf preference in filename gen and lang matching Restore the working IETF language preference that was accidentally removed in the previous commit: - generate_filename_from_track(): use lang_ietf ? lang_ietf : lang for buffer sizing and both snprintf calls - save_vobsub_track(): same lang_tag pattern for base filename - matroska_save_all(): check lang_ietf first (BCP-47), fall back to lang (ISO-639-2) when --mkvlang filter is active; remove now-unused char *match variable The strdup NULL check and broken switch-case removal from the prior commit are unchanged. * matroska: fix clang-format style * matroska: fix filename underscores, LLD macro, braces, param name --- src/lib_ccx/matroska.c | 69 ++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 43 deletions(-) diff --git a/src/lib_ccx/matroska.c b/src/lib_ccx/matroska.c index a89b3b03..3b3d8a81 100644 --- a/src/lib_ccx/matroska.c +++ b/src/lib_ccx/matroska.c @@ -880,6 +880,10 @@ void parse_segment_track_entry(struct matroska_ctx *mkv_ctx) ULLONG track_number = 0; enum matroska_track_entry_type track_type = MATROSKA_TRACK_TYPE_VIDEO; char *lang = strdup("eng"); + if (lang == NULL) + { + fatal(EXIT_NOT_ENOUGH_MEMORY, "In parse_segment_track_entry: Out of memory allocating default language."); + } char *header = NULL; char *lang_ietf = NULL; char *codec_id_string = NULL; @@ -1031,29 +1035,7 @@ void parse_segment_track_entry(struct matroska_ctx *mkv_ctx) case MATROSKA_SEGMENT_TRACK_LANGUAGE_IETF: lang_ietf = read_vint_block_string(file); mprint(" Language IETF: %s\n", lang_ietf); - // We'll store this for later use rather than freeing it immediately - if (track_type == MATROSKA_TRACK_TYPE_SUBTITLE) - { - // Don't free lang_ietf here, store in track - if (lang != NULL) - { - // If we previously allocated lang, free it as we'll prefer IETF - free(lang); - lang = NULL; - } - // Default to "eng" if we somehow don't have a language yet - if (lang == NULL) - { - lang = strdup("eng"); - } - } - else - { - free(lang_ietf); // Free if not a subtitle track - lang_ietf = NULL; - } MATROSKA_SWITCH_BREAK(code, code_len); - /* Misc ids */ case MATROSKA_VOID: read_vint_block_skip(file); @@ -1349,22 +1331,19 @@ void parse_segment(struct matroska_ctx *mkv_ctx) char *generate_filename_from_track(struct matroska_ctx *mkv_ctx, struct matroska_sub_track *track) { - // Use lang_ietf if available, otherwise fall back to lang - const char *lang_to_use = track->lang_ietf ? track->lang_ietf : track->lang; const char *basename = get_basename(mkv_ctx->filename); const char *extension = matroska_track_text_subtitle_id_extensions[track->codec_id]; - - // Calculate needed size: basename + "_" + lang + "_" + index + "." + extension + null - size_t needed = strlen(basename) + strlen(lang_to_use) + strlen(extension) + 32; + /* Prefer the BCP-47 IETF tag (e.g. "zh-Hant") over the legacy + * ISO-639-2 code (e.g. "chi") when one is available. */ + const char *lang_tag = track->lang_ietf ? track->lang_ietf : track->lang; + size_t needed = strlen(basename) + strlen(lang_tag) + strlen(extension) + 32; char *buf = malloc(needed); if (buf == NULL) fatal(EXIT_NOT_ENOUGH_MEMORY, "In generate_filename_from_track: Out of memory."); - if (track->lang_index == 0) - snprintf(buf, needed, "%s_%s.%s", basename, lang_to_use, extension); + snprintf(buf, needed, "%s_%s.%s", basename, lang_tag, extension); else - snprintf(buf, needed, "%s_%s_" LLD ".%s", basename, lang_to_use, - track->lang_index, extension); + snprintf(buf, needed, "%s_%s_" LLD ".%s", basename, lang_tag, track->lang_index, extension); return buf; } @@ -1599,17 +1578,18 @@ static void save_vobsub_track(struct matroska_ctx *mkv_ctx, struct matroska_sub_ } // Generate base filename (without extension) - const char *lang_to_use = track->lang_ietf ? track->lang_ietf : track->lang; const char *basename = get_basename(mkv_ctx->filename); - size_t needed = strlen(basename) + strlen(lang_to_use) + 32; + /* Prefer the BCP-47 IETF tag over the legacy ISO-639-2 code. */ + const char *lang_tag = track->lang_ietf ? track->lang_ietf : track->lang; + size_t needed = strlen(basename) + strlen(lang_tag) + 32; char *base_filename = malloc(needed); if (base_filename == NULL) fatal(EXIT_NOT_ENOUGH_MEMORY, "In save_vobsub_track: Out of memory."); if (track->lang_index == 0) - snprintf(base_filename, needed, "%s_%s", basename, lang_to_use); + snprintf(base_filename, needed, "%s_%s", basename, lang_tag); else - snprintf(base_filename, needed, "%s_%s_" LLD, basename, lang_to_use, track->lang_index); + snprintf(base_filename, needed, "%s_%s_" LLD, basename, lang_tag, track->lang_index); // Create .sub filename char *sub_filename = malloc(needed + 5); @@ -1664,7 +1644,7 @@ static void save_vobsub_track(struct matroska_ctx *mkv_ctx, struct matroska_sub_ // Add language identifier line char lang_line[128]; - snprintf(lang_line, sizeof(lang_line), "\nid: %s, index: 0\n", lang_to_use); + snprintf(lang_line, sizeof(lang_line), "\nid: %s, index: 0\n", track->lang); write_wrapped(idx_desc, lang_line, strlen(lang_line)); // Buffer for PS/PES headers and padding @@ -1710,7 +1690,6 @@ static void save_vobsub_track(struct matroska_ctx *mkv_ctx, struct matroska_sub_ write_wrapped(sub_desc, (char *)zero_buf, padding_needed); bytes_written += padding_needed; } - file_pos += bytes_written; } @@ -1932,17 +1911,21 @@ void free_sub_track(struct matroska_sub_track *track) void matroska_save_all(struct matroska_ctx *mkv_ctx, char *lang) { - char *match; for (int i = 0; i < mkv_ctx->sub_tracks_count; i++) { if (lang) { - // Try to match against IETF tag first if available + /* Match against lang_ietf (BCP-47, e.g. "en-US") first, + * then fall back to lang (ISO-639-2, e.g. "eng"). + * This lets users pass either form to --mkvlang. */ + int matched = 0; if (mkv_ctx->sub_tracks[i]->lang_ietf && - (match = strstr(lang, mkv_ctx->sub_tracks[i]->lang_ietf)) != NULL) - save_sub_track(mkv_ctx, mkv_ctx->sub_tracks[i]); - // Fall back to 3-letter code - else if ((match = strstr(lang, mkv_ctx->sub_tracks[i]->lang)) != NULL) + strstr(lang, mkv_ctx->sub_tracks[i]->lang_ietf) != NULL) + matched = 1; + if (!matched && + strstr(lang, mkv_ctx->sub_tracks[i]->lang) != NULL) + matched = 1; + if (matched) save_sub_track(mkv_ctx, mkv_ctx->sub_tracks[i]); } else