diff --git a/src/mkvmerge.cpp b/src/mkvmerge.cpp index edabcb677..019a7db6b 100644 --- a/src/mkvmerge.cpp +++ b/src/mkvmerge.cpp @@ -400,6 +400,11 @@ void parse_and_add_tags(const char *file_name) { while (tags->ListSize() > 0) { tag = (KaxTag *)(*tags)[0]; + if (!tag->CheckMandatory()) { + mxprint(stderr, "Error parsing the tags in '%s': some mandatory " + "elements are missing.\n", file_name); + exit(1); + } tags->Remove(0); add_tags(tag); } diff --git a/src/tagparser.h b/src/tagparser.h index 15285afdb..87f8a122c 100644 --- a/src/tagparser.h +++ b/src/tagparser.h @@ -118,6 +118,8 @@ using namespace libmatroska; typedef struct { XML_Parser parser; + const char *file_name; + int depth; bool done_reading, data_allowed; diff --git a/src/tagparser_start.cpp b/src/tagparser_start.cpp index 01614fd57..cb3c060e0 100644 --- a/src/tagparser_start.cpp +++ b/src/tagparser_start.cpp @@ -42,6 +42,41 @@ using namespace libmatroska; if (FindChild(*p) != NULL) \ perror_oneinstance(); +template Type &GetEmptyChild(EbmlMaster &master) { + EbmlElement *e; + + e = master.FindFirstElt(Type::ClassInfos, true); + try { + EbmlMaster *m = &dynamic_cast(*e); + if (m != NULL) + while (m->ListSize() > 0) { + delete (*m)[0]; + m->Remove(0); + } + } catch (...) { + } + + return *(static_cast(e)); +} + +template Type &GetNextEmptyChild(EbmlMaster &master, + const Type &past_elt) { + EbmlElement *e; + + e = master.FindNextElt(past_elt, true); + try { + EbmlMaster *m = &dynamic_cast(*e); + if (m != NULL) + while (m->ListSize() > 0) { + delete (*m)[0]; + m->Remove(0); + } + } catch (...) { + } + + return *(static_cast(e)); +} + void start_level1(parser_data_t *pdata, const char *name) { string parent_name; @@ -49,9 +84,9 @@ void start_level1(parser_data_t *pdata, const char *name) { if (!strcmp(name, "Tag")) { if (pdata->tag == NULL) - pdata->tag = &GetChild(*pdata->tags); + pdata->tag = &GetEmptyChild(*pdata->tags); else - pdata->tag = &GetNextChild(*pdata->tags, *pdata->tag); + pdata->tag = &GetNextEmptyChild(*pdata->tags, *pdata->tag); } else perror_nochild(); @@ -66,87 +101,87 @@ void start_level2(parser_data_t *pdata, const char *name) { if (!strcmp(name, "Targets")) { if (pdata->targets == NULL) - pdata->targets = &GetChild(*pdata->tag); + pdata->targets = &GetEmptyChild(*pdata->tag); else perror_oneinstance(); pdata->parents->push_back(E_Targets); } else if (!strcmp(name, "General")) { if (pdata->general == NULL) - pdata->general = &GetChild(*pdata->tag); + pdata->general = &GetEmptyChild(*pdata->tag); else perror_oneinstance(); pdata->parents->push_back(E_General); } else if (!strcmp(name, "Genres")) { if (pdata->genres == NULL) - pdata->genres = &GetChild(*pdata->tag); + pdata->genres = &GetEmptyChild(*pdata->tag); else perror_oneinstance(); pdata->parents->push_back(E_Genres); } else if (!strcmp(name, "AudioSpecific")) { if (pdata->audio_specific == NULL) - pdata->audio_specific = &GetChild(*pdata->tag); + pdata->audio_specific = &GetEmptyChild(*pdata->tag); else perror_oneinstance(); pdata->parents->push_back(E_AudioSpecific); } else if (!strcmp(name, "ImageSpecific")) { if (pdata->image_specific == NULL) - pdata->image_specific = &GetChild(*pdata->tag); + pdata->image_specific = &GetEmptyChild(*pdata->tag); else perror_oneinstance(); pdata->parents->push_back(E_ImageSpecific); } else if (!strcmp(name, "MultiCommercial")) { if (pdata->m_commercial == NULL) - pdata->m_commercial = &GetChild(*pdata->tag); + pdata->m_commercial = &GetEmptyChild(*pdata->tag); else perror_oneinstance(); pdata->parents->push_back(E_MultiCommercial); } else if (!strcmp(name, "MultiDate")) { if (pdata->m_date == NULL) - pdata->m_date = &GetChild(*pdata->tag); + pdata->m_date = &GetEmptyChild(*pdata->tag); else perror_oneinstance(); pdata->parents->push_back(E_MultiDate); } else if (!strcmp(name, "MultiEntity")) { if (pdata->m_entity == NULL) - pdata->m_entity = &GetChild(*pdata->tag); + pdata->m_entity = &GetEmptyChild(*pdata->tag); else perror_oneinstance(); pdata->parents->push_back(E_MultiEntity); } else if (!strcmp(name, "MultiIdentifier")) { if (pdata->m_identifier == NULL) - pdata->m_identifier = &GetChild(*pdata->tag); + pdata->m_identifier = &GetEmptyChild(*pdata->tag); else perror_oneinstance(); pdata->parents->push_back(E_MultiIdentifier); } else if (!strcmp(name, "MultiLegal")) { if (pdata->m_legal == NULL) - pdata->m_legal = &GetChild(*pdata->tag); + pdata->m_legal = &GetEmptyChild(*pdata->tag); else perror_oneinstance(); pdata->parents->push_back(E_MultiLegal); } else if (!strcmp(name, "MultiTitle")) { if (pdata->m_title == NULL) - pdata->m_title = &GetChild(*pdata->tag); + pdata->m_title = &GetEmptyChild(*pdata->tag); else perror_oneinstance(); pdata->parents->push_back(E_MultiTitle); } else if (!strcmp(name, "MultiComment")) { if (pdata->m_comment == NULL) - pdata->m_comment = &GetChild(*pdata->tag); + pdata->m_comment = &GetEmptyChild(*pdata->tag); else pdata->m_comment = - &GetNextChild(*pdata->tag, *pdata->m_comment); + &GetNextEmptyChild(*pdata->tag, *pdata->m_comment); pdata->parents->push_back(E_MultiComment); } else @@ -165,17 +200,17 @@ void start_level3(parser_data_t *pdata, const char *name) { if (!strcmp(name, "TrackUID")) { if (pdata->track_uid == NULL) - pdata->track_uid = &GetChild(*pdata->targets); + pdata->track_uid = &GetEmptyChild(*pdata->targets); else pdata->track_uid = - &GetNextChild(*pdata->targets, *pdata->track_uid); + &GetNextEmptyChild(*pdata->targets, *pdata->track_uid); pdata->parents->push_back(E_TrackUID); } else if (!strcmp(name, "ChapterUID")) { if (pdata->chapter_uid == NULL) - pdata->chapter_uid = &GetChild(*pdata->targets); + pdata->chapter_uid = &GetEmptyChild(*pdata->targets); else pdata->chapter_uid = - &GetNextChild(*pdata->targets, + &GetNextEmptyChild(*pdata->targets, *pdata->chapter_uid); pdata->parents->push_back(E_ChapterUID); @@ -211,20 +246,21 @@ void start_level3(parser_data_t *pdata, const char *name) { pdata->parents->push_back(E_ArchivalLocation); } else if (!strcmp(name, "Keywords")) { if (pdata->keywords == NULL) - pdata->keywords = &GetChild(*pdata->general); + pdata->keywords = &GetEmptyChild(*pdata->general); else pdata->keywords = - &GetNextChild(*pdata->general, *pdata->keywords); + &GetNextEmptyChild(*pdata->general, *pdata->keywords); pdata->parents->push_back(E_Keywords); } else if (!strcmp(name, "Mood")) { check_instances(pdata->general, KaxTagMood); pdata->parents->push_back(E_Mood); } else if (!strcmp(name, "RecordLocation")) { if (pdata->rec_location == NULL) - pdata->rec_location = &GetChild(*pdata->general); + pdata->rec_location = + &GetEmptyChild(*pdata->general); else pdata->rec_location = - &GetNextChild(*pdata->general, + &GetNextEmptyChild(*pdata->general, *pdata->rec_location); pdata->parents->push_back(E_RecordLocation); } else if (!strcmp(name, "Source")) { @@ -253,17 +289,17 @@ void start_level3(parser_data_t *pdata, const char *name) { if (!strcmp(name, "AudioGenre")) { if (pdata->audio_genre == NULL) - pdata->audio_genre = &GetChild(*pdata->genres); + pdata->audio_genre = &GetEmptyChild(*pdata->genres); else pdata->audio_genre = - &GetNextChild(*pdata->genres, *pdata->audio_genre); + &GetNextEmptyChild(*pdata->genres, *pdata->audio_genre); pdata->parents->push_back(E_AudioGenre); } else if (!strcmp(name, "VideoGenre")) { if (pdata->video_genre == NULL) - pdata->video_genre = &GetChild(*pdata->genres); + pdata->video_genre = &GetEmptyChild(*pdata->genres); else pdata->video_genre = - &GetNextChild(*pdata->genres, *pdata->video_genre); + &GetNextEmptyChild(*pdata->genres, *pdata->video_genre); pdata->parents->push_back(E_VideoGenre); } else if (!strcmp(name, "SubGenre")) { check_instances(pdata->genres, KaxTagSubGenre); @@ -334,10 +370,11 @@ void start_level3(parser_data_t *pdata, const char *name) { } else if (parent == E_MultiCommercial) { if (!strcmp(name, "Commercial")) { if (pdata->commercial == NULL) - pdata->commercial = &GetChild(*pdata->m_commercial); + pdata->commercial = + &GetEmptyChild(*pdata->m_commercial); else pdata->commercial = - &GetNextChild(*pdata->m_commercial, + &GetNextEmptyChild(*pdata->m_commercial, *pdata->commercial); pdata->parents->push_back(E_Commercial); } else @@ -346,10 +383,10 @@ void start_level3(parser_data_t *pdata, const char *name) { } else if (parent == E_MultiDate) { if (!strcmp(name, "Date")) { if (pdata->date == NULL) - pdata->date = &GetChild(*pdata->m_date); + pdata->date = &GetEmptyChild(*pdata->m_date); else pdata->date = - &GetNextChild(*pdata->m_date, *pdata->date); + &GetNextEmptyChild(*pdata->m_date, *pdata->date); pdata->parents->push_back(E_Date); } else perror_nochild(); @@ -357,10 +394,10 @@ void start_level3(parser_data_t *pdata, const char *name) { } else if (parent == E_MultiEntity) { if (!strcmp(name, "Entity")) { if (pdata->entity == NULL) - pdata->entity = &GetChild(*pdata->m_entity); + pdata->entity = &GetEmptyChild(*pdata->m_entity); else pdata->entity = - &GetNextChild(*pdata->m_entity, *pdata->entity); + &GetNextEmptyChild(*pdata->m_entity, *pdata->entity); pdata->parents->push_back(E_Entity); } else perror_nochild(); @@ -368,10 +405,11 @@ void start_level3(parser_data_t *pdata, const char *name) { } else if (parent == E_MultiIdentifier) { if (!strcmp(name, "Identifier")) { if (pdata->identifier == NULL) - pdata->identifier = &GetChild(*pdata->m_identifier); + pdata->identifier = + &GetEmptyChild(*pdata->m_identifier); else pdata->identifier = - &GetNextChild(*pdata->m_identifier, + &GetNextEmptyChild(*pdata->m_identifier, *pdata->identifier); pdata->parents->push_back(E_Identifier); } else @@ -380,10 +418,10 @@ void start_level3(parser_data_t *pdata, const char *name) { } else if (parent == E_MultiLegal) { if (!strcmp(name, "Legal")) { if (pdata->legal == NULL) - pdata->legal = &GetChild(*pdata->m_legal); + pdata->legal = &GetEmptyChild(*pdata->m_legal); else pdata->legal = - &GetNextChild(*pdata->m_legal, *pdata->legal); + &GetNextEmptyChild(*pdata->m_legal, *pdata->legal); pdata->parents->push_back(E_Legal); } else perror_nochild(); @@ -391,10 +429,10 @@ void start_level3(parser_data_t *pdata, const char *name) { } else if (parent == E_MultiTitle) { if (!strcmp(name, "Title")) { if (pdata->title == NULL) - pdata->title = &GetChild(*pdata->m_title); + pdata->title = &GetEmptyChild(*pdata->m_title); else pdata->title = - &GetNextChild(*pdata->m_title, *pdata->title); + &GetNextEmptyChild(*pdata->m_title, *pdata->title); pdata->parents->push_back(E_Title); } else perror_nochild(); @@ -421,28 +459,29 @@ void start_level4(parser_data_t *pdata, const char *name) { pdata->parents->push_back(E_Address); } else if (!strcmp(name, "URL")) { if (pdata->c_url == NULL) - pdata->c_url = &GetChild(*pdata->commercial); + pdata->c_url = + &GetEmptyChild(*pdata->commercial); else pdata->c_url = - &GetNextChild(*pdata->commercial, + &GetNextEmptyChild(*pdata->commercial, *pdata->c_url); pdata->parents->push_back(E_URL); } else if (!strcmp(name, "Email")) { if (pdata->c_email == NULL) pdata->c_email = - &GetChild(*pdata->commercial); + &GetEmptyChild(*pdata->commercial); else pdata->c_email = - &GetNextChild(*pdata->commercial, + &GetNextEmptyChild(*pdata->commercial, *pdata->c_email); pdata->parents->push_back(E_Email); } else if (!strcmp(name, "MultiPrice")) { pdata->data_allowed = false; if (pdata->m_price == NULL) - pdata->m_price = &GetChild(*pdata->commercial); + pdata->m_price = &GetEmptyChild(*pdata->commercial); else pdata->m_price = - &GetNextChild(*pdata->commercial, *pdata->m_price); + &GetNextEmptyChild(*pdata->commercial, *pdata->m_price); pdata->parents->push_back(E_MultiPrice); } else perror_nochild(); @@ -473,17 +512,18 @@ void start_level4(parser_data_t *pdata, const char *name) { pdata->parents->push_back(E_Name); } else if (!strcmp(name, "URL")) { if (pdata->e_url == NULL) - pdata->e_url = &GetChild(*pdata->entity); + pdata->e_url = &GetEmptyChild(*pdata->entity); else pdata->e_url = - &GetNextChild(*pdata->entity, *pdata->e_url); + &GetNextEmptyChild(*pdata->entity, *pdata->e_url); pdata->parents->push_back(E_URL); } else if (!strcmp(name, "Email")) { if (pdata->e_email == NULL) - pdata->e_email = &GetChild(*pdata->entity); + pdata->e_email = + &GetEmptyChild(*pdata->entity); else pdata->e_email = - &GetNextChild(*pdata->entity, + &GetNextEmptyChild(*pdata->entity, *pdata->e_email); pdata->parents->push_back(E_Email); } else if (!strcmp(name, "Address")) { @@ -515,10 +555,10 @@ void start_level4(parser_data_t *pdata, const char *name) { pdata->parents->push_back(E_LegalType); } else if (!strcmp(name, "URL")) { if (pdata->l_url == NULL) - pdata->l_url = &GetChild(*pdata->legal); + pdata->l_url = &GetEmptyChild(*pdata->legal); else pdata->l_url = - &GetNextChild(*pdata->legal, *pdata->l_url); + &GetNextEmptyChild(*pdata->legal, *pdata->l_url); pdata->parents->push_back(E_URL); } else if (!strcmp(name, "Address")) { check_instances(pdata->legal, KaxTagMultiLegalAddress); @@ -546,17 +586,17 @@ void start_level4(parser_data_t *pdata, const char *name) { pdata->parents->push_back(E_Address); } else if (!strcmp(name, "URL")) { if (pdata->t_url == NULL) - pdata->t_url = &GetChild(*pdata->title); + pdata->t_url = &GetEmptyChild(*pdata->title); else pdata->t_url = - &GetNextChild(*pdata->title, *pdata->t_url); + &GetNextEmptyChild(*pdata->title, *pdata->t_url); pdata->parents->push_back(E_URL); } else if (!strcmp(name, "Email")) { if (pdata->t_email == NULL) - pdata->t_email = &GetChild(*pdata->title); + pdata->t_email = &GetEmptyChild(*pdata->title); else pdata->t_email = - &GetNextChild(*pdata->title, *pdata->t_email); + &GetNextEmptyChild(*pdata->title, *pdata->t_email); pdata->parents->push_back(E_Email); } else if (!strcmp(name, "Language")) { check_instances(pdata->title, KaxTagMultiTitleLanguage); @@ -641,8 +681,8 @@ void start_element(void *user_data, const char *name, void perror(parser_data_t *pdata, const char *fmt, ...) { va_list ap; - fprintf(stderr, "Tag parsing error, line %d, column %d: ", - XML_GetCurrentLineNumber(pdata->parser), + fprintf(stderr, "Tag parsing error in '%s', line %d, column %d: ", + pdata->file_name, XML_GetCurrentLineNumber(pdata->parser), XML_GetCurrentColumnNumber(pdata->parser)); va_start(ap, fmt); vfprintf(stderr, fmt, ap); @@ -708,6 +748,7 @@ void parse_xml_tags(const char *name, KaxTags *tags) { pdata->tags = tags; pdata->parent_names = new vector; pdata->parents = new vector; + pdata->file_name = name; XML_SetUserData(parser, pdata); XML_SetElementHandler(parser, start_element, end_element);