mirror of
https://gitlab.com/mbunkus/mkvtoolnix.git
synced 2024-12-24 20:01:53 +00:00
Leftovers from the previous merge.
This commit is contained in:
parent
f78d588bd4
commit
9e793ffcdb
@ -1,86 +0,0 @@
|
||||
/*
|
||||
* mkvmerge -- utility for splicing together matroska files
|
||||
* from component media subtypes
|
||||
*
|
||||
* Distributed under the GPL
|
||||
* see the file COPYING for details
|
||||
* or visit http://www.gnu.org/copyleft/gpl.html
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* Mapping from XML elements to EBML elements
|
||||
*
|
||||
* Written by Moritz Bunkus <moritz@bunkus.org>.
|
||||
*/
|
||||
|
||||
#include "ebml/EbmlElement.h"
|
||||
|
||||
#include "chapters.h"
|
||||
|
||||
namespace libmatroska {
|
||||
extern EbmlId KaxChapters_TheId;
|
||||
extern EbmlId KaxEditionEntry_TheId;
|
||||
extern EbmlId KaxEditionUID_TheId;
|
||||
extern EbmlId KaxEditionFlagHidden_TheId;
|
||||
extern EbmlId KaxEditionFlagDefault_TheId;
|
||||
extern EbmlId KaxEditionManaged_TheId;
|
||||
extern EbmlId KaxChapterAtom_TheId;
|
||||
extern EbmlId KaxChapterUID_TheId;
|
||||
extern EbmlId KaxChapterTimeStart_TheId;
|
||||
extern EbmlId KaxChapterTimeEnd_TheId;
|
||||
extern EbmlId KaxChapterFlagHidden_TheId;
|
||||
extern EbmlId KaxChapterFlagEnabled_TheId;
|
||||
extern EbmlId KaxChapterPhysicalEquiv_TheId;
|
||||
extern EbmlId KaxChapterTrack_TheId;
|
||||
extern EbmlId KaxChapterTrackNumber_TheId;
|
||||
extern EbmlId KaxChapterDisplay_TheId;
|
||||
extern EbmlId KaxChapterString_TheId;
|
||||
extern EbmlId KaxChapterLanguage_TheId;
|
||||
extern EbmlId KaxChapterCountry_TheId;
|
||||
extern EbmlId KaxChapterProcess_TheId;
|
||||
extern EbmlId KaxChapterProcessTime_TheId;
|
||||
}
|
||||
|
||||
parser_element_t chapter_elements[] = {
|
||||
{"Chapters", ebmlt_master, 0, 0, 0, KaxChapters_TheId, NULL, NULL},
|
||||
|
||||
{"EditionEntry", ebmlt_master, 1, 0, 0, KaxEditionEntry_TheId, NULL, NULL},
|
||||
{"EditionUID", ebmlt_uint, 2, 0, NO_MAX_VALUE, KaxEditionUID_TheId, NULL,
|
||||
NULL},
|
||||
{"EditionFlagHidden", ebmlt_bool, 2, 0, 0, KaxEditionFlagHidden_TheId,
|
||||
NULL, NULL},
|
||||
{"EditionManaged", ebmlt_uint, 2, 0, NO_MAX_VALUE, KaxEditionManaged_TheId,
|
||||
NULL, NULL},
|
||||
{"EditionFlagDefault", ebmlt_bool, 2, 0, 0, KaxEditionFlagDefault_TheId,
|
||||
NULL, NULL},
|
||||
|
||||
{"ChapterAtom", ebmlt_master, 2, 0, 0, KaxChapterAtom_TheId, NULL,
|
||||
NULL},
|
||||
{"ChapterUID", ebmlt_uint, 3, 0, NO_MAX_VALUE, KaxChapterUID_TheId, NULL,
|
||||
NULL},
|
||||
{"ChapterTimeStart", ebmlt_time, 3, 0, 0, KaxChapterTimeStart_TheId, NULL,
|
||||
NULL},
|
||||
{"ChapterTimeEnd", ebmlt_time, 3, 0, 0, KaxChapterTimeEnd_TheId, NULL,
|
||||
NULL},
|
||||
{"ChapterFlagHidden", ebmlt_bool, 3, 0, 0, KaxChapterFlagHidden_TheId,
|
||||
NULL, NULL},
|
||||
{"ChapterFlagEnabled", ebmlt_bool, 3, 0, 0, KaxChapterFlagEnabled_TheId,
|
||||
NULL, NULL},
|
||||
|
||||
{"ChapterTrack", ebmlt_master, 3, 0, 0, KaxChapterTrack_TheId,
|
||||
NULL, NULL},
|
||||
{"ChapterTrackNumber", ebmlt_uint, 4, 0, NO_MAX_VALUE,
|
||||
KaxChapterTrackNumber_TheId, NULL, NULL},
|
||||
|
||||
{"ChapterDisplay", ebmlt_master, 3, 0, 0, KaxChapterDisplay_TheId,
|
||||
NULL, NULL},
|
||||
{"ChapterString", ebmlt_ustring, 4, 0, 0, KaxChapterString_TheId,
|
||||
NULL, NULL},
|
||||
{"ChapterLanguage", ebmlt_string, 4, 0, 0, KaxChapterLanguage_TheId,
|
||||
NULL, NULL},
|
||||
{"ChapterCountry", ebmlt_string, 4, 0, 0, KaxChapterCountry_TheId,
|
||||
NULL, NULL},
|
||||
|
||||
{NULL, ebmlt_master, 0, 0, 0, EbmlId((uint32_t)0, 0), NULL, NULL}
|
||||
};
|
||||
|
@ -1,45 +0,0 @@
|
||||
/*
|
||||
* mkvmerge -- utility for splicing together matroska files
|
||||
* from component media subtypes
|
||||
*
|
||||
* Distributed under the GPL
|
||||
* see the file COPYING for details
|
||||
* or visit http://www.gnu.org/copyleft/gpl.html
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* Declarations of external EBML Ids found in libebml
|
||||
*
|
||||
* Written by Moritz Bunkus <moritz@bunkus.org>.
|
||||
*/
|
||||
|
||||
#ifndef __EBML_IDS_H
|
||||
#define __EBML_IDS_H
|
||||
|
||||
#include "ebml/EbmlElement.h"
|
||||
|
||||
namespace libmatroska {
|
||||
extern EbmlId KaxChapters_TheId;
|
||||
extern EbmlId KaxEditionEntry_TheId;
|
||||
extern EbmlId KaxEditionUID_TheId;
|
||||
extern EbmlId KaxEditionFlagHidden_TheId;
|
||||
extern EbmlId KaxEditionFlagDefault_TheId;
|
||||
extern EbmlId KaxEditionManaged_TheId;
|
||||
extern EbmlId KaxChapterAtom_TheId;
|
||||
extern EbmlId KaxChapterUID_TheId;
|
||||
extern EbmlId KaxChapterTimeStart_TheId;
|
||||
extern EbmlId KaxChapterTimeEnd_TheId;
|
||||
extern EbmlId KaxChapterFlagHidden_TheId;
|
||||
extern EbmlId KaxChapterFlagEnabled_TheId;
|
||||
extern EbmlId KaxChapterPhysicalEquiv_TheId;
|
||||
extern EbmlId KaxChapterTrack_TheId;
|
||||
extern EbmlId KaxChapterTrackNumber_TheId;
|
||||
extern EbmlId KaxChapterDisplay_TheId;
|
||||
extern EbmlId KaxChapterString_TheId;
|
||||
extern EbmlId KaxChapterLanguage_TheId;
|
||||
extern EbmlId KaxChapterCountry_TheId;
|
||||
extern EbmlId KaxChapterProcess_TheId;
|
||||
extern EbmlId KaxChapterProcessTime_TheId;
|
||||
}
|
||||
|
||||
#endif
|
@ -1,705 +0,0 @@
|
||||
/*
|
||||
* mkvmerge -- utility for splicing together matroska files
|
||||
* from component media subtypes
|
||||
*
|
||||
* Distributed under the GPL
|
||||
* see the file COPYING for details
|
||||
* or visit http://www.gnu.org/copyleft/gpl.html
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* XML tag parser. Functions for the end tags + value parsers
|
||||
*
|
||||
* Written by Moritz Bunkus <moritz@bunkus.org>.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <expat.h>
|
||||
|
||||
#include "base64.h"
|
||||
#include "common.h"
|
||||
#include "commonebml.h"
|
||||
#include "iso639.h"
|
||||
#include "mm_io.h"
|
||||
#include "tagparser.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace libebml;
|
||||
using namespace libmatroska;
|
||||
|
||||
static void
|
||||
el_get_uint(parser_data_t *pdata,
|
||||
EbmlElement *el,
|
||||
uint64_t min_value = 0,
|
||||
uint64_t max_value = 9223372036854775807ULL) {
|
||||
int64 value;
|
||||
|
||||
strip(*pdata->bin);
|
||||
if (!parse_int(pdata->bin->c_str(), value))
|
||||
tperror(pdata, "Expected an unsigned integer but found '%s'.",
|
||||
pdata->bin->c_str());
|
||||
if (value < min_value)
|
||||
tperror(pdata, "Unsigned integer (%lld) is too small. Mininum value is "
|
||||
"%lld.", value, min_value);
|
||||
if (value > max_value)
|
||||
tperror(pdata, "Unsigned integer (%lld) is too big. Maximum value is "
|
||||
"%lld.", value, max_value);
|
||||
|
||||
*(static_cast<EbmlUInteger *>(el)) = value;
|
||||
}
|
||||
|
||||
static void
|
||||
el_get_sint(parser_data_t *pdata,
|
||||
EbmlElement *el,
|
||||
int64_t min_value = -9223372036854775807LL-1) {
|
||||
int64 value;
|
||||
|
||||
strip(*pdata->bin);
|
||||
if (!parse_int(pdata->bin->c_str(), value))
|
||||
tperror(pdata, "Expected a signed integer but found '%s'.",
|
||||
pdata->bin->c_str());
|
||||
if (value < min_value)
|
||||
tperror(pdata, "Signed integer (%lld) is too small. Mininum value is "
|
||||
"%lld.\n", value, min_value);
|
||||
|
||||
*(static_cast<EbmlSInteger *>(el)) = value;
|
||||
}
|
||||
|
||||
static void
|
||||
el_get_float(parser_data_t *pdata,
|
||||
EbmlElement *el,
|
||||
float min_value = (float)1.40129846432481707e-45) {
|
||||
char *endptr;
|
||||
float value;
|
||||
|
||||
strip(*pdata->bin);
|
||||
value = (float)strtod(pdata->bin->c_str(), &endptr);
|
||||
|
||||
if (((value == 0.0) && (endptr == pdata->bin->c_str())) ||
|
||||
(errno == ERANGE))
|
||||
tperror(pdata, "Expected a floating point number but found '%s'.",
|
||||
pdata->bin->c_str());
|
||||
|
||||
*(static_cast<EbmlFloat *>(el)) = value;
|
||||
}
|
||||
|
||||
static void
|
||||
el_get_string(parser_data_t *pdata,
|
||||
EbmlElement *el,
|
||||
bool check_language = false) {
|
||||
strip(*pdata->bin);
|
||||
if (pdata->bin->length() == 0)
|
||||
tperror(pdata, "Expected a string but found only whitespaces.");
|
||||
|
||||
if (check_language && !is_valid_iso639_2_code(pdata->bin->c_str()))
|
||||
tperror(pdata, "'%s' is not a valid ISO639-2 language code. See the "
|
||||
"output of 'mkvmerge --list-languages' for a list of all "
|
||||
"valid language codes.", pdata->bin->c_str());
|
||||
|
||||
*(static_cast<EbmlString *>(el)) = pdata->bin->c_str();
|
||||
}
|
||||
|
||||
static void
|
||||
el_get_utf8string(parser_data_t *pdata,
|
||||
EbmlElement *el) {
|
||||
strip(*pdata->bin);
|
||||
if (pdata->bin->length() == 0)
|
||||
tperror(pdata, "Expected a string but found only whitespaces.");
|
||||
|
||||
*(static_cast<EbmlUnicodeString *>(el)) =
|
||||
cstrutf8_to_UTFstring(pdata->bin->c_str());
|
||||
}
|
||||
|
||||
static void
|
||||
el_get_binary(parser_data_t *pdata,
|
||||
EbmlElement *el) {
|
||||
int64_t result;
|
||||
binary *buffer;
|
||||
mm_io_c *io;
|
||||
|
||||
result = 0;
|
||||
buffer = NULL;
|
||||
strip(*pdata->bin, true);
|
||||
if (pdata->bin->length() == 0)
|
||||
tperror(pdata, "Found neither Base64 encoded data nor '@file' to read "
|
||||
"binary data from.");
|
||||
|
||||
if ((*pdata->bin)[0] == '@') {
|
||||
if (pdata->bin->length() == 1)
|
||||
tperror(pdata, "No filename found after the '@'.");
|
||||
try {
|
||||
io = new mm_io_c(&(pdata->bin->c_str())[1], MODE_READ);
|
||||
io->setFilePointer(0, seek_end);
|
||||
result = io->getFilePointer();
|
||||
io->setFilePointer(0, seek_beginning);
|
||||
if (result <= 0)
|
||||
tperror(pdata, "The file '%s' is empty.", &(pdata->bin->c_str())[1]);
|
||||
buffer = new binary[result];
|
||||
io->read(buffer, result);
|
||||
delete io;
|
||||
} catch(...) {
|
||||
tperror(pdata, "Could not open/read the file '%s'.",
|
||||
&(pdata->bin->c_str())[1]);
|
||||
}
|
||||
|
||||
} else {
|
||||
buffer = new binary[pdata->bin->length() / 4 * 3 + 1];
|
||||
result = base64_decode(*pdata->bin, (unsigned char *)buffer);
|
||||
if (result < 0)
|
||||
tperror(pdata, "Could not decode the Base64 encoded data - it seems to "
|
||||
"be broken.");
|
||||
}
|
||||
|
||||
(static_cast<EbmlBinary *>(el))->SetBuffer(buffer, result);
|
||||
}
|
||||
|
||||
// ISO 8601 format: 2003-07-17T19:50:53+0200
|
||||
// 012345678901234567890123
|
||||
// 1 2
|
||||
static void
|
||||
el_get_date(parser_data_t *pdata,
|
||||
EbmlElement *el) {
|
||||
const char *errmsg = "Expected a date in ISO 8601 format but found '%s'. "
|
||||
"The ISO 8601 date format looks like this: YYYY-MM-DDTHH:MM:SS:-TZTZ, "
|
||||
"e.g. 2003-07-17T19:50:52+0200. The time zone (TZ) may also be negative.";
|
||||
char *p;
|
||||
int year, month, day, hour, minute, second, time_zone, offset;
|
||||
char tz_sign;
|
||||
struct tm t;
|
||||
time_t tme;
|
||||
#ifdef SYS_UNIX
|
||||
struct timezone tz;
|
||||
#else
|
||||
time_t tme_local, tme_gm;
|
||||
#endif
|
||||
|
||||
strip(*pdata->bin);
|
||||
p = safestrdup(pdata->bin->c_str());
|
||||
|
||||
if (pdata->bin->length() != 24)
|
||||
tperror(pdata, errmsg, pdata->bin->c_str());
|
||||
|
||||
if ((p[4] != '-') || (p[7] != '-') || (p[10] != 'T') ||
|
||||
(p[13] != ':') || (p[16] != ':') || (p[19] != '+'))
|
||||
tperror(pdata, errmsg, pdata->bin->c_str());
|
||||
|
||||
p[4] = 0;
|
||||
p[7] = 0;
|
||||
p[10] = 0;
|
||||
p[13] = 0;
|
||||
p[16] = 0;
|
||||
tz_sign = p[19];
|
||||
p[19] = 0;
|
||||
|
||||
if (!parse_int(p, year) || !parse_int(&p[5], month) ||
|
||||
!parse_int(&p[8], day) || !parse_int(&p[11], hour) ||
|
||||
!parse_int(&p[14], minute) || !parse_int(&p[17], second) ||
|
||||
!parse_int(&p[20], time_zone))
|
||||
tperror(pdata, errmsg, pdata->bin->c_str());
|
||||
|
||||
if (year < 1900)
|
||||
tperror(pdata, "Invalid year given (%d).", year);
|
||||
if ((month < 1) || (month > 12))
|
||||
tperror(pdata, "Invalid month given (%d).", month);
|
||||
if ((day < 1) || (day > 31))
|
||||
tperror(pdata, "Invalid day given (%d).", day);
|
||||
if ((hour < 0) || (hour > 23))
|
||||
tperror(pdata, "Invalid hour given (%d).", hour);
|
||||
if ((minute < 0) || (minute > 59))
|
||||
tperror(pdata, "Invalid minute given (%d).", minute);
|
||||
if ((second < 0) || (second > 59))
|
||||
tperror(pdata, "Invalid second given (%d).", second);
|
||||
if ((tz_sign != '+') && (tz_sign != '-'))
|
||||
tperror(pdata, "Invalid time zone given (%c%s).", tz_sign, &p[20]);
|
||||
if ((time_zone < 0) || (time_zone > 1200))
|
||||
tperror(pdata, "Invalid time zone given (%c%s).", tz_sign, &p[20]);
|
||||
|
||||
memset(&t, 0, sizeof(struct tm));
|
||||
t.tm_year = year - 1900;
|
||||
t.tm_mon = month - 1;
|
||||
t.tm_mday = day;
|
||||
t.tm_hour = hour;
|
||||
t.tm_min = minute;
|
||||
t.tm_sec = second;
|
||||
t.tm_isdst = -1;
|
||||
tme = mktime(&t);
|
||||
if (tme == (time_t)-1)
|
||||
tperror(pdata, "Invalid date specified (%s).", pdata->bin->c_str());
|
||||
offset = (((time_zone / 100) * 60) + (time_zone % 100)) * 60;
|
||||
if (tz_sign == '+')
|
||||
offset *= -1;
|
||||
tme += offset;
|
||||
#ifdef SYS_UNIX
|
||||
gettimeofday(NULL, &tz);
|
||||
tme -= tz.tz_minuteswest * 60;
|
||||
#else
|
||||
tme_local = mktime(localtime(&tme));
|
||||
tme_gm = mktime(gmtime(&tme));
|
||||
tme -= (tme_gm - tme_local);
|
||||
#endif
|
||||
if (tme < 0)
|
||||
tperror(pdata, "Invalid date specified (%s).", pdata->bin->c_str());
|
||||
|
||||
safefree(p);
|
||||
|
||||
(static_cast<EbmlDate *>(el))->SetEpochDate(tme);
|
||||
}
|
||||
|
||||
static bool
|
||||
is_multicomment(parser_data_t *pdata,
|
||||
const char *name) {
|
||||
int parent;
|
||||
|
||||
parent = (*pdata->parents)[pdata->parents->size() - 2];
|
||||
|
||||
if (parent != E_MultiComment)
|
||||
return false;
|
||||
|
||||
if (!strcmp(name, "Name"))
|
||||
el_get_string(pdata, &GetChild<KaxTagMultiCommentName>(*pdata->m_comment));
|
||||
else if (!strcmp(name, "Comments"))
|
||||
el_get_utf8string(pdata, &GetChild<KaxTagMultiCommentComments>
|
||||
(*pdata->m_comment));
|
||||
else if (!strcmp(name, "Language"))
|
||||
el_get_string(pdata, &GetChild<KaxTagMultiCommentLanguage>
|
||||
(*pdata->m_comment), true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
end_level1(parser_data_t *pdata,
|
||||
const char *) {
|
||||
// Can only be "Tag"
|
||||
pdata->targets = NULL;
|
||||
pdata->general = NULL;
|
||||
pdata->genres = NULL;
|
||||
pdata->audio_specific = NULL;
|
||||
pdata->image_specific = NULL;
|
||||
pdata->m_commercial = NULL;
|
||||
pdata->m_date = NULL;
|
||||
pdata->m_entity = NULL;
|
||||
pdata->m_identifier = NULL;
|
||||
pdata->m_legal = NULL;
|
||||
pdata->m_title = NULL;
|
||||
pdata->m_comment = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
end_level2(parser_data_t *pdata,
|
||||
const char *name) {
|
||||
if (!strcmp(name, "Targets")) {
|
||||
GetChild<KaxTagTargetTypeValue>(*pdata->targets);
|
||||
pdata->track_uid = NULL;
|
||||
pdata->chapter_uid = NULL;
|
||||
pdata->edition_uid = NULL;
|
||||
pdata->m_comment = NULL;
|
||||
|
||||
} else if (!strcmp(name, "General")) {
|
||||
pdata->keywords = NULL;
|
||||
pdata->rec_location = NULL;
|
||||
pdata->m_comment = NULL;
|
||||
|
||||
} else if (!strcmp(name, "Genres")) {
|
||||
pdata->audio_genre = NULL;
|
||||
pdata->video_genre = NULL;
|
||||
pdata->m_comment = NULL;
|
||||
|
||||
} else if (!strcmp(name, "AudioSpecific")) {
|
||||
pdata->m_comment = NULL;
|
||||
|
||||
} else if (!strcmp(name, "ImageSpecific")) {
|
||||
pdata->m_comment = NULL;
|
||||
|
||||
} else if (!strcmp(name, "MultiCommercial")) {
|
||||
pdata->commercial = NULL;
|
||||
pdata->m_comment = NULL;
|
||||
|
||||
} else if (!strcmp(name, "MultiDate")) {
|
||||
pdata->date = NULL;
|
||||
pdata->m_comment = NULL;
|
||||
|
||||
} else if (!strcmp(name, "MultiEntity")) {
|
||||
pdata->entity = NULL;
|
||||
pdata->m_comment = NULL;
|
||||
|
||||
} else if (!strcmp(name, "MultiIdentifier")) {
|
||||
pdata->identifier = NULL;
|
||||
pdata->m_comment = NULL;
|
||||
|
||||
} else if (!strcmp(name, "MultiLegal")) {
|
||||
pdata->legal = NULL;
|
||||
pdata->m_comment = NULL;
|
||||
|
||||
} else if (!strcmp(name, "MultiTitle")) {
|
||||
pdata->title = NULL;
|
||||
pdata->m_comment = NULL;
|
||||
|
||||
} else if (!strcmp(name, "MultiComment")) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
end_level3(parser_data_t *pdata,
|
||||
const char *name) {
|
||||
string parent_name;
|
||||
int parent;
|
||||
|
||||
if (is_multicomment(pdata, name))
|
||||
return;
|
||||
|
||||
parent_name = (*pdata->parent_names)[pdata->parent_names->size() - 2];
|
||||
parent = (*pdata->parents)[pdata->parents->size() - 2];
|
||||
|
||||
if (parent == E_Targets) {
|
||||
if (!strcmp(name, "TrackUID"))
|
||||
el_get_uint(pdata, pdata->track_uid);
|
||||
else if (!strcmp(name, "ChapterUID"))
|
||||
el_get_uint(pdata, pdata->chapter_uid);
|
||||
else if (!strcmp(name, "EditionUID"))
|
||||
el_get_uint(pdata, pdata->edition_uid);
|
||||
else if (!strcmp(name, "TargetType"))
|
||||
el_get_string(pdata, &GetChild<KaxTagTargetType>(*pdata->targets));
|
||||
|
||||
} else if (parent == E_General) {
|
||||
if (!strcmp(name, "Subject"))
|
||||
el_get_utf8string(pdata, &GetChild<KaxTagSubject>(*pdata->general));
|
||||
else if (!strcmp(name, "Bibliography"))
|
||||
el_get_utf8string(pdata, &GetChild<KaxTagBibliography>(*pdata->general));
|
||||
else if (!strcmp(name, "Language"))
|
||||
el_get_string(pdata, &GetChild<KaxTagLanguage>(*pdata->general), true);
|
||||
else if (!strcmp(name, "Rating"))
|
||||
el_get_binary(pdata, &GetChild<KaxTagRating>(*pdata->general));
|
||||
else if (!strcmp(name, "Encoder"))
|
||||
el_get_utf8string(pdata, &GetChild<KaxTagEncoder>(*pdata->general));
|
||||
else if (!strcmp(name, "EncodeSettings"))
|
||||
el_get_utf8string(pdata,
|
||||
&GetChild<KaxTagEncodeSettings>(*pdata->general));
|
||||
else if (!strcmp(name, "File"))
|
||||
el_get_utf8string(pdata, &GetChild<KaxTagFile>(*pdata->general));
|
||||
else if (!strcmp(name, "ArchivalLocation"))
|
||||
el_get_utf8string(pdata,
|
||||
&GetChild<KaxTagArchivalLocation>(*pdata->general));
|
||||
else if (!strcmp(name, "Keywords"))
|
||||
el_get_utf8string(pdata, pdata->keywords);
|
||||
else if (!strcmp(name, "Mood"))
|
||||
el_get_utf8string(pdata, &GetChild<KaxTagMood>(*pdata->general));
|
||||
else if (!strcmp(name, "RecordLocation"))
|
||||
el_get_string(pdata, pdata->rec_location);
|
||||
else if (!strcmp(name, "Source"))
|
||||
el_get_utf8string(pdata, &GetChild<KaxTagSource>(*pdata->general));
|
||||
else if (!strcmp(name, "SourceForm"))
|
||||
el_get_utf8string(pdata, &GetChild<KaxTagSourceForm>(*pdata->general));
|
||||
else if (!strcmp(name, "Product"))
|
||||
el_get_utf8string(pdata, &GetChild<KaxTagProduct>(*pdata->general));
|
||||
else if (!strcmp(name, "OriginalMediaType"))
|
||||
el_get_utf8string(pdata,
|
||||
&GetChild<KaxTagOriginalMediaType>(*pdata->general));
|
||||
else if (!strcmp(name, "PlayCounter"))
|
||||
el_get_uint(pdata, &GetChild<KaxTagPlayCounter>(*pdata->general));
|
||||
else if (!strcmp(name, "Popularimeter"))
|
||||
el_get_sint(pdata, &GetChild<KaxTagPopularimeter>(*pdata->general));
|
||||
|
||||
} else if (parent == E_Genres) {
|
||||
if (!strcmp(name, "AudioGenre"))
|
||||
el_get_string(pdata, pdata->audio_genre);
|
||||
else if (!strcmp(name, "VideoGenre"))
|
||||
el_get_binary(pdata, pdata->video_genre);
|
||||
else if (!strcmp(name, "SubGenre"))
|
||||
el_get_string(pdata, &GetChild<KaxTagSubGenre>(*pdata->genres));
|
||||
|
||||
} else if (parent == E_AudioSpecific) {
|
||||
if (!strcmp(name, "AudioEncryption"))
|
||||
el_get_binary(pdata,
|
||||
&GetChild<KaxTagAudioEncryption>(*pdata->audio_specific));
|
||||
else if (!strcmp(name, "AudioGain"))
|
||||
el_get_float(pdata,
|
||||
&GetChild<KaxTagAudioGain>(*pdata->audio_specific),
|
||||
0.000000001);
|
||||
else if (!strcmp(name, "AudioPeak"))
|
||||
el_get_float(pdata, &GetChild<KaxTagAudioPeak>(*pdata->audio_specific));
|
||||
else if (!strcmp(name, "BPM"))
|
||||
el_get_float(pdata, &GetChild<KaxTagBPM>(*pdata->audio_specific));
|
||||
else if (!strcmp(name, "Equalisation"))
|
||||
el_get_binary(pdata,
|
||||
&GetChild<KaxTagEqualisation>(*pdata->audio_specific));
|
||||
else if (!strcmp(name, "DiscTrack"))
|
||||
el_get_uint(pdata, &GetChild<KaxTagDiscTrack>(*pdata->audio_specific));
|
||||
else if (!strcmp(name, "SetPart"))
|
||||
el_get_uint(pdata, &GetChild<KaxTagSetPart>(*pdata->audio_specific));
|
||||
else if (!strcmp(name, "InitialKey"))
|
||||
el_get_string(pdata,
|
||||
&GetChild<KaxTagInitialKey>(*pdata->audio_specific));
|
||||
else if (!strcmp(name, "OfficialAudioFileURL"))
|
||||
el_get_string(pdata, &GetChild<KaxTagOfficialAudioFileURL>
|
||||
(*pdata->audio_specific));
|
||||
else if (!strcmp(name, "OfficialAudioSourceURL"))
|
||||
el_get_string(pdata, &GetChild<KaxTagOfficialAudioSourceURL>
|
||||
(*pdata->audio_specific));
|
||||
|
||||
} else if (parent == E_ImageSpecific) {
|
||||
if (!strcmp(name, "CaptureDPI"))
|
||||
el_get_uint(pdata, &GetChild<KaxTagCaptureDPI>(*pdata->image_specific));
|
||||
else if (!strcmp(name, "CaptureLightness"))
|
||||
el_get_binary(pdata, &GetChild<KaxTagCaptureLightness>
|
||||
(*pdata->image_specific));
|
||||
else if (!strcmp(name, "CapturePaletteSetting"))
|
||||
el_get_uint(pdata, &GetChild<KaxTagCapturePaletteSetting>
|
||||
(*pdata->image_specific));
|
||||
else if (!strcmp(name, "CaptureSharpness"))
|
||||
el_get_binary(pdata, &GetChild<KaxTagCaptureSharpness>
|
||||
(*pdata->image_specific));
|
||||
else if (!strcmp(name, "Cropped"))
|
||||
el_get_utf8string(pdata, &GetChild<KaxTagCropped>
|
||||
(*pdata->image_specific));
|
||||
else if (!strcmp(name, "OriginalDimensions"))
|
||||
el_get_string(pdata, &GetChild<KaxTagOriginalDimensions>
|
||||
(*pdata->image_specific));
|
||||
|
||||
} else if (parent == E_MultiCommercial) {
|
||||
pdata->c_url = NULL;
|
||||
pdata->c_email = NULL;
|
||||
pdata->m_price = NULL;
|
||||
pdata->m_comment = NULL;
|
||||
|
||||
} else if (parent == E_MultiDate) {
|
||||
pdata->m_comment = NULL;
|
||||
|
||||
} else if (parent == E_MultiEntity) {
|
||||
pdata->e_url = NULL;
|
||||
pdata->e_email = NULL;
|
||||
pdata->m_comment = NULL;
|
||||
|
||||
} else if (parent == E_MultiIdentifier) {
|
||||
pdata->m_comment = NULL;
|
||||
|
||||
} else if (parent == E_MultiLegal) {
|
||||
pdata->l_url = NULL;
|
||||
pdata->m_comment = NULL;
|
||||
|
||||
} else if (parent == E_MultiTitle) {
|
||||
pdata->t_url = NULL;
|
||||
pdata->t_email = NULL;
|
||||
pdata->m_comment = NULL;
|
||||
|
||||
} else
|
||||
die("Unknown parent: level 3, %d", parent);
|
||||
}
|
||||
|
||||
static void
|
||||
end_level4(parser_data_t *pdata,
|
||||
const char *name) {
|
||||
string parent_name;
|
||||
int parent;
|
||||
|
||||
if (is_multicomment(pdata, name))
|
||||
return;
|
||||
|
||||
parent_name = (*pdata->parent_names)[pdata->parent_names->size() - 2];
|
||||
parent = (*pdata->parents)[pdata->parents->size() - 2];
|
||||
|
||||
if (parent == E_Commercial) {
|
||||
if (!strcmp(name, "CommercialType"))
|
||||
el_get_uint(pdata, &GetChild<KaxTagMultiCommercialType>
|
||||
(*pdata->commercial), 1);
|
||||
else if (!strcmp(name, "Address"))
|
||||
el_get_utf8string(pdata, &GetChild<KaxTagMultiCommercialAddress>
|
||||
(*pdata->commercial));
|
||||
else if (!strcmp(name, "URL"))
|
||||
el_get_string(pdata, pdata->c_url);
|
||||
else if (!strcmp(name, "Email"))
|
||||
el_get_string(pdata, pdata->c_email);
|
||||
else if (!strcmp(name, "MultiPrice")) {
|
||||
pdata->m_comment = NULL;
|
||||
}
|
||||
|
||||
} else if (parent == E_Date) {
|
||||
if (!strcmp(name, "DateType"))
|
||||
el_get_uint(pdata, &GetChild<KaxTagMultiDateType>
|
||||
(*pdata->date), 1);
|
||||
else if (!strcmp(name, "Begin"))
|
||||
el_get_date(pdata, &GetChild<KaxTagMultiDateDateBegin>
|
||||
(*pdata->date));
|
||||
else if (!strcmp(name, "End"))
|
||||
el_get_date(pdata, &GetChild<KaxTagMultiDateDateEnd>
|
||||
(*pdata->date));
|
||||
|
||||
} else if (parent == E_Entity) {
|
||||
if (!strcmp(name, "EntityType"))
|
||||
el_get_uint(pdata, &GetChild<KaxTagMultiEntityType>
|
||||
(*pdata->entity), 1);
|
||||
else if (!strcmp(name, "Name"))
|
||||
el_get_utf8string(pdata, &GetChild<KaxTagMultiEntityName>
|
||||
(*pdata->entity));
|
||||
else if (!strcmp(name, "URL"))
|
||||
el_get_string(pdata, pdata->e_url);
|
||||
else if (!strcmp(name, "Email"))
|
||||
el_get_string(pdata, pdata->e_email);
|
||||
else if (!strcmp(name, "Address"))
|
||||
el_get_utf8string(pdata, &GetChild<KaxTagMultiEntityAddress>
|
||||
(*pdata->entity));
|
||||
|
||||
} else if (parent == E_Identifier) {
|
||||
if (!strcmp(name, "IdentifierType"))
|
||||
el_get_uint(pdata, &GetChild<KaxTagMultiIdentifierType>
|
||||
(*pdata->identifier), 1);
|
||||
else if (!strcmp(name, "Binary"))
|
||||
el_get_binary(pdata, &GetChild<KaxTagMultiIdentifierBinary>
|
||||
(*pdata->identifier));
|
||||
else if (!strcmp(name, "String"))
|
||||
el_get_utf8string(pdata, &GetChild<KaxTagMultiIdentifierString>
|
||||
(*pdata->identifier));
|
||||
|
||||
} else if (parent == E_Legal) {
|
||||
if (!strcmp(name, "LegalType"))
|
||||
el_get_uint(pdata, &GetChild<KaxTagMultiLegalType>
|
||||
(*pdata->legal), 1);
|
||||
else if (!strcmp(name, "URL"))
|
||||
el_get_string(pdata, pdata->l_url);
|
||||
else if (!strcmp(name, "Address"))
|
||||
el_get_utf8string(pdata, &GetChild<KaxTagMultiLegalAddress>
|
||||
(*pdata->legal));
|
||||
else if (!strcmp(name, "Content"))
|
||||
el_get_utf8string(pdata, &GetChild<KaxTagMultiLegalContent>
|
||||
(*pdata->legal));
|
||||
|
||||
} else if (parent == E_Title) {
|
||||
if (!strcmp(name, "TitleType"))
|
||||
el_get_uint(pdata, &GetChild<KaxTagMultiTitleType>
|
||||
(*pdata->title), 1);
|
||||
else if (!strcmp(name, "Name"))
|
||||
el_get_utf8string(pdata, &GetChild<KaxTagMultiTitleName>
|
||||
(*pdata->title));
|
||||
else if (!strcmp(name, "SubTitle"))
|
||||
el_get_utf8string(pdata, &GetChild<KaxTagMultiTitleSubTitle>
|
||||
(*pdata->title));
|
||||
else if (!strcmp(name, "Edition"))
|
||||
el_get_utf8string(pdata, &GetChild<KaxTagMultiTitleEdition>
|
||||
(*pdata->title));
|
||||
else if (!strcmp(name, "Address"))
|
||||
el_get_utf8string(pdata, &GetChild<KaxTagMultiTitleAddress>
|
||||
(*pdata->title));
|
||||
else if (!strcmp(name, "URL"))
|
||||
el_get_string(pdata, pdata->t_url);
|
||||
else if (!strcmp(name, "Email"))
|
||||
el_get_string(pdata, pdata->t_email);
|
||||
else if (!strcmp(name, "Language"))
|
||||
el_get_string(pdata, &GetChild<KaxTagMultiTitleLanguage>
|
||||
(*pdata->title), true);
|
||||
|
||||
} else
|
||||
die("Unknown parent: level 4, %d", parent);
|
||||
}
|
||||
|
||||
static void
|
||||
end_level5(parser_data_t *pdata,
|
||||
const char *name) {
|
||||
string parent_name;
|
||||
int parent;
|
||||
|
||||
if (is_multicomment(pdata, name))
|
||||
return;
|
||||
|
||||
parent_name = (*pdata->parent_names)[pdata->parent_names->size() - 2];
|
||||
parent = (*pdata->parents)[pdata->parents->size() - 2];
|
||||
|
||||
if (parent == E_MultiPrice) {
|
||||
if (!strcmp(name, "Currency"))
|
||||
el_get_string(pdata, &GetChild<KaxTagMultiPriceCurrency>
|
||||
(*pdata->m_price));
|
||||
else if (!strcmp(name, "Amount"))
|
||||
el_get_float(pdata, &GetChild<KaxTagMultiPriceAmount>
|
||||
(*pdata->m_price));
|
||||
else if (!strcmp(name, "PriceDate"))
|
||||
el_get_date(pdata, &GetChild<KaxTagMultiPricePriceDate>
|
||||
(*pdata->m_price));
|
||||
|
||||
} else
|
||||
die("Unknown parent: level 4, %d", parent);
|
||||
}
|
||||
|
||||
static void
|
||||
end_level6(parser_data_t *pdata,
|
||||
const char *name) {
|
||||
if (is_multicomment(pdata, name))
|
||||
return;
|
||||
|
||||
die("tagparser_end: Unknown element. This should not have happened.");
|
||||
}
|
||||
|
||||
static void
|
||||
end_simple(parser_data_t *pdata,
|
||||
const char *name) {
|
||||
|
||||
if (!strcmp(name, "Simple")) {
|
||||
pdata->simple_tags->pop_back();
|
||||
if (pdata->simple_tags->size() == 0)
|
||||
pdata->parsing_simple = false;
|
||||
|
||||
} else {
|
||||
KaxTagSimple *simple =
|
||||
(*pdata->simple_tags)[pdata->simple_tags->size() - 1];
|
||||
if (!strcmp(name, "Name"))
|
||||
el_get_utf8string(pdata, &GetChild<KaxTagName>(*simple));
|
||||
else if (!strcmp(name, "String"))
|
||||
el_get_utf8string(pdata, &GetChild<KaxTagString>(*simple));
|
||||
else if (!strcmp(name, "Binary"))
|
||||
el_get_binary(pdata, &GetChild<KaxTagBinary>(*simple));
|
||||
else if (!strcmp(name, "TagLanguage"))
|
||||
el_get_string(pdata, &GetChild<KaxTagLangue>(*simple), true);
|
||||
else if (!strcmp(name, "DefaultLanguage"))
|
||||
el_get_uint(pdata, &GetChild<KaxTagDefault>(*simple), 0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
end_xml_tag_element(void *user_data,
|
||||
const char *name) {
|
||||
parser_data_t *pdata;
|
||||
|
||||
pdata = (parser_data_t *)user_data;
|
||||
|
||||
if (pdata->data_allowed && (pdata->bin == NULL))
|
||||
tperror(pdata, "Element <%s> does not contain any data.", name);
|
||||
|
||||
if (pdata->parsing_simple)
|
||||
end_simple(pdata, name);
|
||||
else if (pdata->depth == 1)
|
||||
; // Nothing to do here!
|
||||
else if (pdata->depth == 2)
|
||||
end_level1(pdata, name);
|
||||
else if (pdata->depth == 3)
|
||||
end_level2(pdata, name);
|
||||
else if (pdata->depth == 4)
|
||||
end_level3(pdata, name);
|
||||
else if (pdata->depth == 5)
|
||||
end_level4(pdata, name);
|
||||
else if (pdata->depth == 6)
|
||||
end_level5(pdata, name);
|
||||
else if (pdata->depth == 7)
|
||||
end_level6(pdata, name);
|
||||
else
|
||||
die("tagparser_end: depth > 7: %d", pdata->depth);
|
||||
|
||||
if (pdata->bin != NULL) {
|
||||
delete pdata->bin;
|
||||
pdata->bin = NULL;
|
||||
}
|
||||
|
||||
pdata->data_allowed = false;
|
||||
pdata->depth--;
|
||||
pdata->parent_names->pop_back();
|
||||
pdata->parents->pop_back();
|
||||
}
|
@ -1,479 +0,0 @@
|
||||
/*
|
||||
* mkvmerge -- utility for splicing together matroska files
|
||||
* from component media subtypes
|
||||
*
|
||||
* Distributed under the GPL
|
||||
* see the file COPYING for details
|
||||
* or visit http://www.gnu.org/copyleft/gpl.html
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* XML tag parser. Functions for the start tags + helper functions
|
||||
*
|
||||
* Written by Moritz Bunkus <moritz@bunkus.org>.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <setjmp.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <expat.h>
|
||||
|
||||
#include "base64.h"
|
||||
#include "common.h"
|
||||
#include "commonebml.h"
|
||||
#include "mm_io.h"
|
||||
#include "tagparser.h"
|
||||
#include "xml_element_mapping.h"
|
||||
|
||||
#include <matroska/KaxTags.h>
|
||||
#include <matroska/KaxTag.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace libebml;
|
||||
using namespace libmatroska;
|
||||
|
||||
typedef struct {
|
||||
XML_Parser parser;
|
||||
|
||||
const char *file_name;
|
||||
|
||||
int depth;
|
||||
bool done_reading, data_allowed;
|
||||
|
||||
string *bin;
|
||||
|
||||
vector<EbmlElement *> *parents;
|
||||
vector<int> *parent_idxs;
|
||||
|
||||
KaxTags *tags;
|
||||
|
||||
jmp_buf parse_error_jmp;
|
||||
string *parse_error_msg;
|
||||
} parser_data_t;
|
||||
|
||||
#define parent_elt (*((parser_data_t *)pdata)->parents) \
|
||||
[((parser_data_t *)pdata)->parents->size() - 1]
|
||||
#define parent_name _parent_name(parent_elt)
|
||||
#define CPDATA (parser_data_t *)pdata
|
||||
|
||||
static const char *
|
||||
_parent_name(EbmlElement *e) {
|
||||
int i;
|
||||
|
||||
for (i = 0; tag_elements[i].name != NULL; i++)
|
||||
if (tag_elements[i].id == e->Generic().GlobalId)
|
||||
return tag_elements[i].name;
|
||||
|
||||
return "(none)";
|
||||
}
|
||||
|
||||
static void
|
||||
tperror(parser_data_t *pdata,
|
||||
const char *fmt,
|
||||
...) {
|
||||
va_list ap;
|
||||
string new_fmt;
|
||||
char *new_string;
|
||||
int len;
|
||||
|
||||
fix_format(fmt, new_fmt);
|
||||
len = get_arg_len("Error: Tag parser failed for '%s', line %d, "
|
||||
"column %d: ", pdata->file_name,
|
||||
XML_GetCurrentLineNumber(pdata->parser),
|
||||
XML_GetCurrentColumnNumber(pdata->parser));
|
||||
va_start(ap, fmt);
|
||||
len += get_varg_len(new_fmt.c_str(), ap);
|
||||
new_string = (char *)safemalloc(len + 2);
|
||||
sprintf(new_string, "Error: Tag parser failed for '%s', line %d, "
|
||||
"column %d: ", pdata->file_name,
|
||||
XML_GetCurrentLineNumber(pdata->parser),
|
||||
XML_GetCurrentColumnNumber(pdata->parser));
|
||||
vsprintf(&new_string[strlen(new_string)], new_fmt.c_str(), ap);
|
||||
va_end(ap);
|
||||
strcat(new_string, "\n");
|
||||
*pdata->parse_error_msg = new_string;
|
||||
safefree(new_string);
|
||||
longjmp(pdata->parse_error_jmp, 1);
|
||||
}
|
||||
|
||||
static void
|
||||
el_get_uint(parser_data_t *pdata,
|
||||
EbmlElement *el,
|
||||
uint64_t min_value = 0,
|
||||
bool is_bool = false) {
|
||||
int64 value;
|
||||
|
||||
strip(*pdata->bin);
|
||||
if (!parse_int(pdata->bin->c_str(), value))
|
||||
tperror(pdata, "Expected an unsigned integer but found '%s'.",
|
||||
pdata->bin->c_str());
|
||||
if (value < min_value)
|
||||
tperror(pdata, "Unsigned integer (%lld) is too small. Mininum value is "
|
||||
"%lld.", value, min_value);
|
||||
if (is_bool && (value > 0))
|
||||
value = 1;
|
||||
|
||||
*(static_cast<EbmlUInteger *>(el)) = value;
|
||||
}
|
||||
|
||||
static void
|
||||
el_get_string(parser_data_t *pdata,
|
||||
EbmlElement *el) {
|
||||
strip(*pdata->bin);
|
||||
if (pdata->bin->length() == 0)
|
||||
tperror(pdata, "Expected a string but found only whitespaces.");
|
||||
|
||||
*(static_cast<EbmlString *>(el)) = pdata->bin->c_str();
|
||||
}
|
||||
|
||||
static void
|
||||
el_get_utf8string(parser_data_t *pdata,
|
||||
EbmlElement *el) {
|
||||
strip(*pdata->bin);
|
||||
if (pdata->bin->length() == 0)
|
||||
tperror(pdata, "Expected a string but found only whitespaces.");
|
||||
|
||||
*(static_cast<EbmlUnicodeString *>(el)) =
|
||||
cstrutf8_to_UTFstring(pdata->bin->c_str());
|
||||
}
|
||||
|
||||
static void
|
||||
el_get_binary(parser_data_t *pdata,
|
||||
EbmlElement *el) {
|
||||
int64_t result;
|
||||
binary *buffer;
|
||||
mm_io_c *io;
|
||||
|
||||
result = 0;
|
||||
buffer = NULL;
|
||||
strip(*pdata->bin, true);
|
||||
if (pdata->bin->length() == 0)
|
||||
tperror(pdata, "Found neither Base64 encoded data nor '@file' to read "
|
||||
"binary data from.");
|
||||
|
||||
if ((*pdata->bin)[0] == '@') {
|
||||
if (pdata->bin->length() == 1)
|
||||
tperror(pdata, "No filename found after the '@'.");
|
||||
try {
|
||||
io = new mm_io_c(&(pdata->bin->c_str())[1], MODE_READ);
|
||||
io->setFilePointer(0, seek_end);
|
||||
result = io->getFilePointer();
|
||||
io->setFilePointer(0, seek_beginning);
|
||||
if (result <= 0)
|
||||
tperror(pdata, "The file '%s' is empty.", &(pdata->bin->c_str())[1]);
|
||||
buffer = new binary[result];
|
||||
io->read(buffer, result);
|
||||
delete io;
|
||||
} catch(...) {
|
||||
tperror(pdata, "Could not open/read the file '%s'.",
|
||||
&(pdata->bin->c_str())[1]);
|
||||
}
|
||||
|
||||
} else {
|
||||
buffer = new binary[pdata->bin->length() / 4 * 3 + 1];
|
||||
result = base64_decode(*pdata->bin, (unsigned char *)buffer);
|
||||
if (result < 0)
|
||||
tperror(pdata, "Could not decode the Base64 encoded data - it seems to "
|
||||
"be broken.");
|
||||
}
|
||||
|
||||
(static_cast<EbmlBinary *>(el))->SetBuffer(buffer, result);
|
||||
}
|
||||
|
||||
static void
|
||||
add_data(void *user_data,
|
||||
const XML_Char *s,
|
||||
int len) {
|
||||
parser_data_t *pdata;
|
||||
int i;
|
||||
|
||||
pdata = (parser_data_t *)user_data;
|
||||
|
||||
if (!pdata->data_allowed) {
|
||||
for (i = 0; i < len; i++)
|
||||
if (!isblanktab(s[i]) && !iscr(s[i]))
|
||||
tperror(pdata, "Data is not allowed inside <%s>.", parent_name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pdata->bin == NULL)
|
||||
pdata->bin = new string;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
(*pdata->bin) += s[i];
|
||||
}
|
||||
|
||||
static void
|
||||
start_element(void *user_data,
|
||||
const char *name,
|
||||
const char **atts) {
|
||||
parser_data_t *pdata;
|
||||
|
||||
pdata = (parser_data_t *)user_data;
|
||||
|
||||
if (atts[0] != NULL)
|
||||
tperror(pdata, "Attributes are not allowed.");
|
||||
|
||||
if (pdata->data_allowed)
|
||||
tperror(pdata, "<%s> is not a valid child element of <%s>.", name,
|
||||
parent_name);
|
||||
|
||||
pdata->data_allowed = false;
|
||||
|
||||
if (pdata->bin != NULL)
|
||||
die("start_element: pdata->bin != NULL");
|
||||
|
||||
if (pdata->depth == 0) {
|
||||
if (pdata->done_reading)
|
||||
tperror(pdata, "More than one root element found.");
|
||||
if (strcmp(name, "Tags"))
|
||||
tperror(pdata, "Root element must be <Tags>.");
|
||||
|
||||
pdata->parents->push_back(pdata->tags);
|
||||
pdata->parent_idxs->push_back(0);
|
||||
|
||||
} else {
|
||||
EbmlElement *e;
|
||||
EbmlMaster *m;
|
||||
int elt_idx, parent_idx, i;
|
||||
bool found;
|
||||
|
||||
parent_idx = (*pdata->parent_idxs)[pdata->parent_idxs->size() - 1];
|
||||
elt_idx = parent_idx;
|
||||
found = false;
|
||||
while (tag_elements[elt_idx].name != NULL) {
|
||||
if (!strcmp(tag_elements[elt_idx].name, name)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
elt_idx++;
|
||||
}
|
||||
|
||||
if (!found)
|
||||
tperror(pdata, "<%s> is not a valid child element of <%s>.", name,
|
||||
tag_elements[parent_idx].name);
|
||||
|
||||
const EbmlSemanticContext &context =
|
||||
find_ebml_callbacks(KaxTags::ClassInfos,
|
||||
tag_elements[parent_idx].id).Context;
|
||||
found = false;
|
||||
for (i = 0; i < context.Size; i++)
|
||||
if (tag_elements[elt_idx].id ==
|
||||
context.MyTable[i].GetCallbacks.GlobalId) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!found)
|
||||
tperror(pdata, "<%s> is not a valid child element of <%s>.", name,
|
||||
tag_elements[parent_idx].name);
|
||||
|
||||
const EbmlSemantic &semantic =
|
||||
find_ebml_semantic(KaxTags::ClassInfos,
|
||||
tag_elements[elt_idx].id);
|
||||
if (semantic.Unique) {
|
||||
m = dynamic_cast<EbmlMaster *>(parent_elt);
|
||||
assert(m != NULL);
|
||||
for (i = 0; i < m->ListSize(); i++)
|
||||
if ((*m)[i]->Generic().GlobalId == tag_elements[elt_idx].id)
|
||||
tperror(pdata, "Only one instance of <%s> is allowed beneath <%s>.",
|
||||
name, tag_elements[parent_idx].name);
|
||||
}
|
||||
|
||||
e = create_ebml_element(KaxTags::ClassInfos,
|
||||
tag_elements[elt_idx].id);
|
||||
assert(e != NULL);
|
||||
m = dynamic_cast<EbmlMaster *>(parent_elt);
|
||||
assert(m != NULL);
|
||||
m->PushElement(*e);
|
||||
|
||||
if (tag_elements[elt_idx].start_hook != NULL)
|
||||
tag_elements[elt_idx].start_hook(pdata);
|
||||
|
||||
pdata->parents->push_back(e);
|
||||
pdata->parent_idxs->push_back(elt_idx);
|
||||
|
||||
pdata->data_allowed = tag_elements[elt_idx].type != ebmlt_master;
|
||||
}
|
||||
|
||||
(pdata->depth)++;
|
||||
}
|
||||
|
||||
static void
|
||||
end_element(void *user_data,
|
||||
const char *name) {
|
||||
parser_data_t *pdata;
|
||||
EbmlMaster *m;
|
||||
|
||||
pdata = (parser_data_t *)user_data;
|
||||
|
||||
if (pdata->data_allowed && (pdata->bin == NULL))
|
||||
tperror(pdata, "Element <%s> does not contain any data.", name);
|
||||
|
||||
if (pdata->depth == 1) {
|
||||
m = static_cast<EbmlMaster *>(parent_elt);
|
||||
if (m->ListSize() == 0)
|
||||
tperror(pdata, "At least one <EditionEntry> element is needed.");
|
||||
|
||||
} else {
|
||||
int elt_idx;
|
||||
bool found;
|
||||
|
||||
found = false;
|
||||
for (elt_idx = 0; tag_elements[elt_idx].name != NULL; elt_idx++)
|
||||
if (!strcmp(tag_elements[elt_idx].name, name)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
assert(found);
|
||||
|
||||
switch (tag_elements[elt_idx].type) {
|
||||
case ebmlt_master:
|
||||
break;
|
||||
case ebmlt_uint:
|
||||
el_get_uint(pdata, parent_elt, tag_elements[elt_idx].min_value,
|
||||
false);
|
||||
break;
|
||||
case ebmlt_bool:
|
||||
el_get_uint(pdata, parent_elt, 0, true);
|
||||
break;
|
||||
case ebmlt_string:
|
||||
el_get_string(pdata, parent_elt);
|
||||
break;
|
||||
case ebmlt_ustring:
|
||||
el_get_utf8string(pdata, parent_elt);
|
||||
break;
|
||||
case ebmlt_binary:
|
||||
el_get_binary(pdata, parent_elt);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
if (tag_elements[elt_idx].end_hook != NULL)
|
||||
tag_elements[elt_idx].end_hook(pdata);
|
||||
}
|
||||
|
||||
if (pdata->bin != NULL) {
|
||||
delete pdata->bin;
|
||||
pdata->bin = NULL;
|
||||
}
|
||||
|
||||
pdata->data_allowed = false;
|
||||
pdata->depth--;
|
||||
pdata->parents->pop_back();
|
||||
pdata->parent_idxs->pop_back();
|
||||
}
|
||||
|
||||
static void
|
||||
end_simple_tag(void *pdata) {
|
||||
KaxTagSimple *simple;
|
||||
|
||||
simple = dynamic_cast<KaxTagSimple *>(parent_elt);
|
||||
assert(simple != NULL);
|
||||
if ((FINDFIRST(simple, KaxTagString) != NULL) &&
|
||||
(FINDFIRST(simple, KaxTagBinary) != NULL))
|
||||
tperror(CPDATA, "Only one of <String> and <Binary> may be used beneath "
|
||||
"<Simple> but not both at the same time.");
|
||||
}
|
||||
|
||||
void
|
||||
parse_xml_tags(const char *name,
|
||||
KaxTags *tags) {
|
||||
char buffer[5000];
|
||||
int len, done, i;
|
||||
parser_data_t *pdata;
|
||||
mm_io_c *io;
|
||||
XML_Parser parser;
|
||||
XML_Error xerror;
|
||||
char *emsg;
|
||||
|
||||
io = NULL;
|
||||
try {
|
||||
io = new mm_io_c(name, MODE_READ);
|
||||
} catch(...) {
|
||||
mxerror("Could not open '%s' for reading.\n", name);
|
||||
}
|
||||
|
||||
done = 0;
|
||||
|
||||
for (i = 0; tag_elements[i].name != NULL; i++) {
|
||||
tag_elements[i].start_hook = NULL;
|
||||
tag_elements[i].end_hook = NULL;
|
||||
}
|
||||
tag_elements[tag_element_map_index("Simple")].end_hook = end_simple_tag;
|
||||
|
||||
parser = XML_ParserCreate(NULL);
|
||||
|
||||
pdata = (parser_data_t *)safemalloc(sizeof(parser_data_t));
|
||||
memset(pdata, 0, sizeof(parser_data_t));
|
||||
|
||||
pdata->parser = parser;
|
||||
pdata->file_name = name;
|
||||
pdata->parents = new vector<EbmlElement *>;
|
||||
pdata->parent_idxs = new vector<int>;
|
||||
pdata->parse_error_msg = new string;
|
||||
pdata->tags = tags;
|
||||
|
||||
XML_SetUserData(parser, pdata);
|
||||
XML_SetElementHandler(parser, start_element, end_element);
|
||||
XML_SetCharacterDataHandler(parser, add_data);
|
||||
|
||||
if (setjmp(pdata->parse_error_jmp) == 1)
|
||||
mxerror(pdata->parse_error_msg->c_str());
|
||||
do {
|
||||
len = io->read(buffer, 5000);
|
||||
if (len != 5000)
|
||||
done = 1;
|
||||
if (XML_Parse(parser, buffer, len, done) == 0) {
|
||||
xerror = XML_GetErrorCode(parser);
|
||||
if (xerror == XML_ERROR_INVALID_TOKEN)
|
||||
emsg = " Remember that special characters like &, <, > and \" "
|
||||
"must be escaped in the usual HTML way: & for '&', "
|
||||
"< for '<', > for '>' and " for '\"'.";
|
||||
else
|
||||
emsg = "";
|
||||
mxerror("XML parser error at line %d of '%s': %s.%s Aborting.\n",
|
||||
XML_GetCurrentLineNumber(parser), name,
|
||||
XML_ErrorString(xerror), emsg);
|
||||
}
|
||||
|
||||
} while (!done);
|
||||
|
||||
delete io;
|
||||
XML_ParserFree(parser);
|
||||
delete pdata->parents;
|
||||
delete pdata->parent_idxs;
|
||||
safefree(pdata);
|
||||
}
|
||||
|
||||
void
|
||||
fix_mandatory_tag_elements(EbmlElement *e) {
|
||||
if (dynamic_cast<KaxTagSimple *>(e) != NULL) {
|
||||
KaxTagSimple &s = *static_cast<KaxTagSimple *>(e);
|
||||
GetChild<KaxTagLangue>(s);
|
||||
GetChild<KaxTagDefault>(s);
|
||||
|
||||
} else if (dynamic_cast<KaxTagTargets *>(e) != NULL) {
|
||||
KaxTagTargets &t = *static_cast<KaxTagTargets *>(e);
|
||||
GetChild<KaxTagTargetTypeValue>(t);
|
||||
|
||||
}
|
||||
|
||||
if (dynamic_cast<EbmlMaster *>(e) != NULL) {
|
||||
EbmlMaster *m;
|
||||
int i;
|
||||
|
||||
m = static_cast<EbmlMaster *>(e);
|
||||
for (i = 0; i < m->ListSize(); i++)
|
||||
fix_mandatory_tag_elements((*m)[i]);
|
||||
}
|
||||
}
|
@ -17,7 +17,7 @@ T_016cuesheet:701de008087d3e3be9ad34621df8d6c2:passed:20040825-175700
|
||||
T_017chapters:d123294267704fd88f6d730a6ad5f970-3bf90270c5b8abcee3c68b23ff038176:passed:20040825-175700
|
||||
T_018attachments:de6a7f61b9c707dbf8b635abdc95f6f6-61bd952ae52eb9b4cd331dc805e3af0c:passed:20040825-175700
|
||||
T_019attachments2:73eee65d12723bc0d7e3ebfbd9b7c27e-5326411491c8d8f14f09efac0c134d5f-73eee65d12723bc0d7e3ebfbd9b7c27e-5a6e6eeea02af14a78361a7032228c2a:passed:20040825-175700
|
||||
T_020languages:654d90f508b44b4cf3d2a44ffb12dae0:passed:20040825-234208
|
||||
T_020languages:654d90f508b44b4cf3d2a44ffb12dae0:failed:20040825-234208
|
||||
T_021aspect_ratio:22bd828492ccc4a16a8918d6535b8f26-aaf9ad30cf4d23219088df35fb18f396:passed:20040825-234244
|
||||
T_022display_dimensions:d8918ad515a670b30f2d927e29034675:passed:20040825-234339
|
||||
T_023no_x:b934ba7d0e44d79c7a4a020da90cfc3a-a4db5d036681d15ef61e7b2c099e09bc-c95a138583be3bc614ab57e6cbbb14cd:passed:20040825-234343
|
||||
|
Loading…
Reference in New Issue
Block a user